зеркало из https://github.com/microsoft/STL.git
`<tuple>`, `<utility>`: Make `tuple`-related functions ADL-proof (#4488)
This commit is contained in:
Родитель
2175098dee
Коммит
4787efeae1
|
@ -1053,7 +1053,7 @@ _NODISCARD constexpr typename _Tuple_cat1<_Tuples...>::_Ret tuple_cat(_Tuples&&.
|
|||
using _Ret = typename _Cat1::_Ret;
|
||||
using _Kx_seq = typename _Cat1::_Kx_seq;
|
||||
using _Ix_seq = typename _Cat1::_Ix_seq;
|
||||
return _Tuple_cat<_Ret>(_Kx_seq{}, _Ix_seq{}, _STD forward_as_tuple(_STD forward<_Tuples>(_Tpls)...));
|
||||
return _STD _Tuple_cat<_Ret>(_Kx_seq{}, _Ix_seq{}, _STD forward_as_tuple(_STD forward<_Tuples>(_Tpls)...));
|
||||
}
|
||||
|
||||
#if _HAS_CXX17
|
||||
|
@ -1073,9 +1073,9 @@ _EXPORT_STD template <class _Callable, _Tuple_like _Tuple>
|
|||
_EXPORT_STD template <class _Callable, class _Tuple>
|
||||
#endif // ^^^ !_HAS_CXX23 ^^^
|
||||
constexpr decltype(auto) apply(_Callable&& _Obj, _Tuple&& _Tpl) noexcept(
|
||||
noexcept(_Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl),
|
||||
noexcept(_STD _Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl),
|
||||
make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{}))) {
|
||||
return _Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl),
|
||||
return _STD _Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl),
|
||||
make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{});
|
||||
}
|
||||
|
||||
|
@ -1097,10 +1097,10 @@ _EXPORT_STD template <class _Ty, _Tuple_like _Tuple>
|
|||
#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv
|
||||
_EXPORT_STD template <class _Ty, class _Tuple>
|
||||
#endif // ^^^ !_HAS_CXX23 ^^^
|
||||
_NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_Make_from_tuple_impl<_Ty>(
|
||||
_NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_STD _Make_from_tuple_impl<_Ty>(
|
||||
_STD forward<_Tuple>(_Tpl), make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{}))) /* strengthened */ {
|
||||
// construct _Ty from the elements of _Tpl
|
||||
return _Make_from_tuple_impl<_Ty>(
|
||||
return _STD _Make_from_tuple_impl<_Ty>(
|
||||
_STD forward<_Tuple>(_Tpl), make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{});
|
||||
}
|
||||
#endif // _HAS_CXX17
|
||||
|
|
|
@ -304,7 +304,8 @@ struct pair { // store a pair of values
|
|||
|
||||
template <class _Tuple1, class _Tuple2, size_t... _Indices1, size_t... _Indices2>
|
||||
constexpr pair(_Tuple1& _Val1, _Tuple2& _Val2, index_sequence<_Indices1...>, index_sequence<_Indices2...>)
|
||||
: first(_Tuple_get<_Indices1>(_STD move(_Val1))...), second(_Tuple_get<_Indices2>(_STD move(_Val2))...) {}
|
||||
: first(_STD _Tuple_get<_Indices1>(_STD move(_Val1))...),
|
||||
second(_STD _Tuple_get<_Indices2>(_STD move(_Val2))...) {}
|
||||
|
||||
template <class... _Types1, class... _Types2>
|
||||
_CONSTEXPR20 pair(piecewise_construct_t, tuple<_Types1...> _Val1, tuple<_Types2...> _Val2)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -10,6 +11,10 @@
|
|||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if _HAS_CXX17
|
||||
#include <string_view>
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#if _HAS_CXX20
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
|
@ -21,8 +26,26 @@ using namespace std;
|
|||
|
||||
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
|
||||
|
||||
#if _HAS_CXX17
|
||||
#define CONSTEXPR17 constexpr
|
||||
#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv
|
||||
#define CONSTEXPR17 inline
|
||||
#endif // ^^^ !_HAS_CXX17 ^^^
|
||||
|
||||
#if _HAS_CXX20
|
||||
#define CONSTEXPR20 constexpr
|
||||
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
|
||||
#define CONSTEXPR20 inline
|
||||
#endif // ^^^ !_HAS_CXX20 ^^^
|
||||
|
||||
#if _HAS_CXX23
|
||||
#define CONSTEXPR23 constexpr
|
||||
#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv
|
||||
#define CONSTEXPR23 inline
|
||||
#endif // ^^^ !_HAS_CXX23 ^^^
|
||||
|
||||
template <template <typename...> class PairOrTuple>
|
||||
void test_value_categories() {
|
||||
constexpr void test_value_categories() {
|
||||
int n1 = 10;
|
||||
const int n2 = 20;
|
||||
int n3 = 30;
|
||||
|
@ -56,7 +79,7 @@ void test_value_categories() {
|
|||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
constexpr bool test() {
|
||||
{
|
||||
tuple<> x;
|
||||
|
||||
|
@ -131,6 +154,169 @@ int main() {
|
|||
}
|
||||
|
||||
{
|
||||
int w = 11, x = 22, y = 33, z = 44;
|
||||
|
||||
tuple<int&, const int&, int&&, const int&&> t0(w, x, move(y), move(z));
|
||||
|
||||
assert(&get<0>(t0) == &w);
|
||||
assert(&get<1>(t0) == &x);
|
||||
assert(&get<2>(t0) == &y);
|
||||
assert(&get<3>(t0) == &z);
|
||||
|
||||
auto t1 = tuple_cat(make_tuple(50, 60), move(t0), make_tuple(70, 80));
|
||||
|
||||
STATIC_ASSERT(is_same_v<decltype(t1), tuple<int, int, int&, const int&, int&&, const int&&, int, int>>);
|
||||
|
||||
assert(t1 == make_tuple(50, 60, 11, 22, 33, 44, 70, 80));
|
||||
assert(&get<2>(t1) == &w);
|
||||
assert(&get<3>(t1) == &x);
|
||||
assert(&get<4>(t1) == &y);
|
||||
assert(&get<5>(t1) == &z);
|
||||
}
|
||||
|
||||
test_value_categories<pair>();
|
||||
test_value_categories<tuple>();
|
||||
|
||||
{
|
||||
array<int, 3> a1{{-1, -2, -3}};
|
||||
const array<char, 4> a2{{'C', 'A', 'T', 'S'}};
|
||||
|
||||
{
|
||||
auto cat5 = tuple_cat(a1, a2);
|
||||
STATIC_ASSERT(is_same_v<decltype(cat5), tuple<int, int, int, char, char, char, char>>);
|
||||
assert(cat5 == make_tuple(-1, -2, -3, 'C', 'A', 'T', 'S'));
|
||||
}
|
||||
|
||||
{
|
||||
auto cat6 = tuple_cat(move(a1), move(a2));
|
||||
STATIC_ASSERT(is_same_v<decltype(cat6), tuple<int, int, int, char, char, char, char>>);
|
||||
assert(cat6 == make_tuple(-1, -2, -3, 'C', 'A', 'T', 'S'));
|
||||
}
|
||||
}
|
||||
|
||||
// Also test C++17 apply() and make_from_tuple().
|
||||
#if _HAS_CXX17
|
||||
{
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
constexpr int add(int z) const {
|
||||
return x + y + z;
|
||||
}
|
||||
};
|
||||
|
||||
const Point p{100, 20};
|
||||
|
||||
assert(apply(&Point::add, make_tuple(&p, 3)) == 123);
|
||||
|
||||
assert(make_from_tuple<string_view>(make_tuple("Hello world!", static_cast<size_t>(5))) == "Hello");
|
||||
}
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
// Also test VSO-181496 "Variadic template emits spurious warning C4100: unreferenced formal parameter".
|
||||
{
|
||||
assert(tuple_cat() == tuple<>{});
|
||||
|
||||
#if _HAS_CXX17
|
||||
assert(apply([] { return 1729; }, tuple<>{}) == 1729);
|
||||
|
||||
assert(make_from_tuple<int>(tuple<>{}) == 0);
|
||||
#endif // _HAS_CXX17
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef _M_CEE // TRANSITION, VSO-1659496
|
||||
// Also test GH-140 "STL: We should _STD qualify _Ugly function calls to avoid ADL"
|
||||
template <class T>
|
||||
struct holder {
|
||||
T t;
|
||||
};
|
||||
|
||||
struct incomplete;
|
||||
using validator = holder<incomplete>*;
|
||||
|
||||
constexpr bool test_adl_proof() {
|
||||
// Function calls are intentionally qualified.
|
||||
|
||||
auto concatenated = std::tuple_cat(std::make_tuple(validator{}), std::make_tuple(42));
|
||||
STATIC_ASSERT(is_same_v<decltype(concatenated), tuple<validator, int>>);
|
||||
|
||||
assert(std::get<0>(concatenated) == nullptr);
|
||||
assert(std::get<1>(concatenated) == 42);
|
||||
|
||||
#if _HAS_CXX17
|
||||
assert(std::make_from_tuple<validator>(std::make_tuple(validator{})) == nullptr);
|
||||
assert(std::apply([](auto) { return 42; }, std::make_tuple(validator{})) == 42);
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // ^^^ no workaround ^^^
|
||||
|
||||
CONSTEXPR17 bool test_using_lambda() {
|
||||
pair<int, int> p(11, 22);
|
||||
|
||||
const char* const s = "meow";
|
||||
|
||||
array<short, 0> zero;
|
||||
|
||||
array<int, 1> one = {{40}};
|
||||
|
||||
array<long, 2> two = {{50L, 60L}};
|
||||
|
||||
auto make_array = [] {
|
||||
array<char, 3> ret = {{'x', 'y', 'z'}};
|
||||
return ret;
|
||||
};
|
||||
|
||||
const auto t = tuple_cat(p, make_pair(33U, s), zero, one, two, make_array(), make_tuple(1234LL));
|
||||
|
||||
STATIC_ASSERT(is_same_v<decltype(t),
|
||||
const tuple<int, int, unsigned int, const char*, int, long, long, char, char, char, long long>>);
|
||||
|
||||
assert(t == make_tuple(11, 22, 33U, s, 40, 50L, 60L, 'x', 'y', 'z', 1234LL));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CONSTEXPR20 bool test_bind_and_piecewise_construction() {
|
||||
// Also test VSO-181496 "Variadic template emits spurious warning C4100: unreferenced formal parameter".
|
||||
auto b1 = bind([] { return 256; });
|
||||
assert(b1() == 256);
|
||||
|
||||
auto b2 = bind([](int i) { return i * 3; }, b1);
|
||||
assert(b2() == 768);
|
||||
|
||||
const pair<int, int> p(piecewise_construct, tuple<>{}, tuple<>{});
|
||||
assert(p.first == 0);
|
||||
assert(p.second == 0);
|
||||
|
||||
#ifndef _M_CEE // TRANSITION, VSO-1659496
|
||||
const pair<validator, int> p2(piecewise_construct, tuple<validator>{}, tuple<int>{});
|
||||
assert(p2.first == nullptr);
|
||||
assert(p2.second == 0);
|
||||
#endif // ^^^ no workaround ^^^
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if _HAS_CXX17
|
||||
// Also test C++17 make_from_tuple() and C++20 constexpr string.
|
||||
CONSTEXPR20 bool test_make_from_tuple_and_string() {
|
||||
assert(make_from_tuple<string>(tuple<>{}).empty());
|
||||
assert(make_from_tuple<string>(make_tuple(static_cast<size_t>(5), 's')) == "sssss");
|
||||
|
||||
assert(make_from_tuple<wstring>(tuple<>{}).empty());
|
||||
assert(make_from_tuple<wstring>(make_tuple(static_cast<size_t>(5), L's')) == L"sssss");
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
CONSTEXPR23 bool test_unique_ptr_and_string() {
|
||||
unique_ptr<int> up;
|
||||
|
||||
up.reset(new int(10));
|
||||
|
@ -164,75 +350,12 @@ int main() {
|
|||
assert(*get<8>(t0) == 30);
|
||||
assert(get<9>(t0) == 44);
|
||||
assert(get<10>(t0) == 55);
|
||||
}
|
||||
|
||||
{
|
||||
int w = 11, x = 22, y = 33, z = 44;
|
||||
|
||||
tuple<int&, const int&, int&&, const int&&> t0(w, x, move(y), move(z));
|
||||
|
||||
assert(&get<0>(t0) == &w);
|
||||
assert(&get<1>(t0) == &x);
|
||||
assert(&get<2>(t0) == &y);
|
||||
assert(&get<3>(t0) == &z);
|
||||
|
||||
auto t1 = tuple_cat(make_tuple(50, 60), move(t0), make_tuple(70, 80));
|
||||
|
||||
STATIC_ASSERT(is_same_v<decltype(t1), tuple<int, int, int&, const int&, int&&, const int&&, int, int>>);
|
||||
|
||||
assert(t1 == make_tuple(50, 60, 11, 22, 33, 44, 70, 80));
|
||||
assert(&get<2>(t1) == &w);
|
||||
assert(&get<3>(t1) == &x);
|
||||
assert(&get<4>(t1) == &y);
|
||||
assert(&get<5>(t1) == &z);
|
||||
}
|
||||
|
||||
{
|
||||
pair<int, int> p(11, 22);
|
||||
|
||||
const char* const s = "meow";
|
||||
|
||||
array<short, 0> zero;
|
||||
|
||||
array<int, 1> one = {{40}};
|
||||
|
||||
array<long, 2> two = {{50L, 60L}};
|
||||
|
||||
auto make_array = [] {
|
||||
array<char, 3> ret = {{'x', 'y', 'z'}};
|
||||
return ret;
|
||||
};
|
||||
|
||||
const auto t = tuple_cat(p, make_pair(33U, s), zero, one, two, make_array(), make_tuple(1234LL));
|
||||
|
||||
STATIC_ASSERT(is_same_v<decltype(t),
|
||||
const tuple<int, int, unsigned int, const char*, int, long, long, char, char, char, long long>>);
|
||||
|
||||
assert(t == make_tuple(11, 22, 33U, s, 40, 50L, 60L, 'x', 'y', 'z', 1234LL));
|
||||
}
|
||||
|
||||
test_value_categories<pair>();
|
||||
test_value_categories<tuple>();
|
||||
|
||||
{
|
||||
array<int, 3> a1{{-1, -2, -3}};
|
||||
const array<char, 4> a2{{'C', 'A', 'T', 'S'}};
|
||||
|
||||
{
|
||||
auto cat5 = tuple_cat(a1, a2);
|
||||
STATIC_ASSERT(is_same_v<decltype(cat5), tuple<int, int, int, char, char, char, char>>);
|
||||
assert(cat5 == make_tuple(-1, -2, -3, 'C', 'A', 'T', 'S'));
|
||||
}
|
||||
|
||||
{
|
||||
auto cat6 = tuple_cat(move(a1), move(a2));
|
||||
STATIC_ASSERT(is_same_v<decltype(cat6), tuple<int, int, int, char, char, char, char>>);
|
||||
assert(cat6 == make_tuple(-1, -2, -3, 'C', 'A', 'T', 'S'));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if _HAS_CXX20
|
||||
{
|
||||
void test_subrange_and_containers() {
|
||||
using ranges::subrange, ranges::subrange_kind;
|
||||
|
||||
list<int> lst = {10, 20, 30, 40, 50};
|
||||
|
@ -251,53 +374,11 @@ int main() {
|
|||
auto cat7 = tuple_cat(lst_subrange, vec_subrange);
|
||||
STATIC_ASSERT(is_same_v<decltype(cat7), tuple<LstIter, LstIter, VecIter, VecConstIter>>);
|
||||
assert(cat7 == make_tuple(next(lst.begin()), prev(lst.end()), vec.begin() + 1, vec.cend() - 1));
|
||||
}
|
||||
}
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
// Also test C++17 apply() and make_from_tuple().
|
||||
#if _HAS_CXX17
|
||||
{
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
int add(int z) const {
|
||||
return x + y + z;
|
||||
}
|
||||
};
|
||||
|
||||
const Point p{100, 20};
|
||||
|
||||
assert(apply(&Point::add, make_tuple(&p, 3)) == 123);
|
||||
|
||||
assert(make_from_tuple<string>(make_tuple(static_cast<size_t>(5), 's')) == "sssss");
|
||||
}
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
// Also test VSO-181496 "Variadic template emits spurious warning C4100: unreferenced formal parameter".
|
||||
{
|
||||
auto b1 = bind([] { return 256; });
|
||||
assert(b1() == 256);
|
||||
|
||||
auto b2 = bind([](int i) { return i * 3; }, b1);
|
||||
assert(b2() == 768);
|
||||
|
||||
const pair<int, int> p(piecewise_construct, tuple<>{}, tuple<>{});
|
||||
assert(p.first == 0);
|
||||
assert(p.second == 0);
|
||||
|
||||
assert(tuple_cat() == tuple<>{});
|
||||
|
||||
#if _HAS_CXX17
|
||||
assert(apply([] { return 1729; }, tuple<>{}) == 1729);
|
||||
|
||||
assert(make_from_tuple<int>(tuple<>{}) == 0);
|
||||
#endif // _HAS_CXX17
|
||||
}
|
||||
|
||||
// LWG-3211 std::tuple<> should be trivially constructible
|
||||
STATIC_ASSERT(is_trivially_default_constructible_v<tuple<>>);
|
||||
}
|
||||
// LWG-3211 std::tuple<> should be trivially constructible
|
||||
STATIC_ASSERT(is_trivially_default_constructible_v<tuple<>>);
|
||||
|
||||
// Also test DevDiv-1205400 "C++ compiler: static_assert in std::tuple_element prevents SFINAE".
|
||||
template <typename T, typename = void>
|
||||
|
@ -318,3 +399,38 @@ struct HasTupleSize<T, void_t<typename tuple_size<T>::type>> : true_type {};
|
|||
|
||||
STATIC_ASSERT(!HasTupleSize<int>::value);
|
||||
STATIC_ASSERT(HasTupleSize<tuple<short, long>>::value);
|
||||
|
||||
STATIC_ASSERT(test());
|
||||
|
||||
#ifndef _M_CEE // TRANSITION, VSO-1659496
|
||||
STATIC_ASSERT(test_adl_proof());
|
||||
#endif // ^^^ no workaround ^^^
|
||||
|
||||
#if _HAS_CXX17
|
||||
STATIC_ASSERT(test_using_lambda());
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#if _HAS_CXX20
|
||||
STATIC_ASSERT(test_bind_and_piecewise_construction());
|
||||
STATIC_ASSERT(test_make_from_tuple_and_string());
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
#if _HAS_CXX23
|
||||
STATIC_ASSERT(test_unique_ptr_and_string());
|
||||
#endif // _HAS_CXX23
|
||||
|
||||
int main() {
|
||||
test();
|
||||
#ifndef _M_CEE // TRANSITION, VSO-1659496
|
||||
test_adl_proof();
|
||||
#endif // ^^^ no workaround ^^^
|
||||
test_using_lambda();
|
||||
test_bind_and_piecewise_construction();
|
||||
#if _HAS_CXX17
|
||||
test_make_from_tuple_and_string();
|
||||
#endif // _HAS_CXX17
|
||||
#if _HAS_CXX20
|
||||
test_subrange_and_containers();
|
||||
#endif //_HAS_CXX20
|
||||
test_unique_ptr_and_string();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче