Implement C++17 tuple bits. Including apply and make_from_tuple.
This patch upgrades <tuple> to be C++17 compliant by implementing: * tuple_size_v: This was forgotten when implementing the other _v traits. * std::apply: This was added via LFTS v1 in p0220r1. * std::make_from_tuple: This was added in p0209r2. llvm-svn: 275745
This commit is contained in:
parent
aa2417835e
commit
03e29a2964
|
@ -76,10 +76,18 @@ template <class... T> tuple<V...> make_tuple(T&&...); // constexpr in C++14
|
|||
template <class... T> tuple<ATypes...> forward_as_tuple(T&&...) noexcept; // constexpr in C++14
|
||||
template <class... T> tuple<T&...> tie(T&...) noexcept; // constexpr in C++14
|
||||
template <class... Tuples> tuple<CTypes...> tuple_cat(Tuples&&... tpls); // constexpr in C++14
|
||||
|
||||
|
||||
// [tuple.apply], calling a function with a tuple of arguments:
|
||||
template <class F, class Tuple>
|
||||
constexpr decltype(auto) apply(F&& f, Tuple&& t); // C++17
|
||||
template <class T, class Tuple>
|
||||
constexpr T make_from_tuple(Tuple&& t); // C++17
|
||||
|
||||
// 20.4.1.4, tuple helper classes:
|
||||
template <class T> class tuple_size; // undefined
|
||||
template <class... T> class tuple_size<tuple<T...>>;
|
||||
template <class T>
|
||||
constexpr size_t tuple_size_v = tuple_size<T>::value; // C++17
|
||||
template <size_t I, class T> class tuple_element; // undefined
|
||||
template <size_t I, class... T> class tuple_element<I, tuple<T...>>;
|
||||
template <size_t I, class T>
|
||||
|
@ -1361,6 +1369,50 @@ pair<_T1, _T2>::pair(piecewise_construct_t,
|
|||
|
||||
#endif // _LIBCPP_HAS_NO_VARIADICS
|
||||
|
||||
#if _LIBCPP_STD_VER > 14
|
||||
template <class _Tp>
|
||||
constexpr size_t tuple_size_v = tuple_size<_Tp>::value;
|
||||
|
||||
#define _LIBCPP_NOEXCEPT_RETURN(...) noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; }
|
||||
|
||||
template <class _Fn, class _Tuple, size_t ..._Id>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
constexpr decltype(auto) __apply_tuple_impl(_Fn && __f, _Tuple && __t,
|
||||
__tuple_indices<_Id...>)
|
||||
_LIBCPP_NOEXCEPT_RETURN(
|
||||
_VSTD::__invoke_constexpr(
|
||||
_VSTD::forward<_Fn>(__f),
|
||||
_VSTD::get<_Id>(_VSTD::forward<_Tuple>(__t))...)
|
||||
)
|
||||
|
||||
template <class _Fn, class _Tuple>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
constexpr decltype(auto) apply(_Fn && __f, _Tuple && __t)
|
||||
_LIBCPP_NOEXCEPT_RETURN(
|
||||
_VSTD::__apply_tuple_impl(
|
||||
_VSTD::forward<_Fn>(__f), _VSTD::forward<_Tuple>(__t),
|
||||
typename __make_tuple_indices<tuple_size_v<decay_t<_Tuple>>>::type{})
|
||||
)
|
||||
|
||||
template <class _Tp, class _Tuple, size_t... _Idx>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>)
|
||||
_LIBCPP_NOEXCEPT_RETURN(
|
||||
_Tp(_VSTD::get<_Idx>(_VSTD::forward<_Tuple>(__t))...)
|
||||
)
|
||||
|
||||
template <class _Tp, class _Tuple>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
constexpr _Tp make_from_tuple(_Tuple&& __t)
|
||||
_LIBCPP_NOEXCEPT_RETURN(
|
||||
_VSTD::__make_from_tuple_impl<_Tp>(_VSTD::forward<_Tuple>(__t),
|
||||
typename __make_tuple_indices<tuple_size_v<decay_t<_Tuple>>>::type{})
|
||||
)
|
||||
|
||||
#undef _LIBCPP_NOEXCEPT_RETURN
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 14
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP_TUPLE
|
||||
|
|
|
@ -0,0 +1,275 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
|
||||
|
||||
// Test with different ref/ptr/cv qualified argument types.
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "type_id.h"
|
||||
|
||||
// std::array is explicitly allowed to be initialized with A a = { init-list };.
|
||||
// Disable the missing braces warning for this reason.
|
||||
#include "disable_missing_braces_warning.h"
|
||||
|
||||
|
||||
constexpr int constexpr_sum_fn() { return 0; }
|
||||
|
||||
template <class ...Ints>
|
||||
constexpr int constexpr_sum_fn(int x1, Ints... rest) { return x1 + constexpr_sum_fn(rest...); }
|
||||
|
||||
struct ConstexprSumT {
|
||||
constexpr ConstexprSumT() = default;
|
||||
template <class ...Ints>
|
||||
constexpr int operator()(Ints... values) const {
|
||||
return constexpr_sum_fn(values...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void test_constexpr_evaluation()
|
||||
{
|
||||
constexpr ConstexprSumT sum_obj{};
|
||||
{
|
||||
using Tup = std::tuple<>;
|
||||
using Fn = int(&)();
|
||||
constexpr Tup t;
|
||||
static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 0, "");
|
||||
static_assert(std::apply(sum_obj, t) == 0, "");
|
||||
}
|
||||
{
|
||||
using Tup = std::tuple<int>;
|
||||
using Fn = int(&)(int);
|
||||
constexpr Tup t(42);
|
||||
static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 42, "");
|
||||
static_assert(std::apply(sum_obj, t) == 42, "");
|
||||
}
|
||||
{
|
||||
using Tup = std::tuple<int, long>;
|
||||
using Fn = int(&)(int, int);
|
||||
constexpr Tup t(42, 101);
|
||||
static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, "");
|
||||
static_assert(std::apply(sum_obj, t) == 143, "");
|
||||
}
|
||||
{
|
||||
using Tup = std::pair<int, long>;
|
||||
using Fn = int(&)(int, int);
|
||||
constexpr Tup t(42, 101);
|
||||
static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, "");
|
||||
static_assert(std::apply(sum_obj, t) == 143, "");
|
||||
}
|
||||
{
|
||||
using Tup = std::tuple<int, long, int>;
|
||||
using Fn = int(&)(int, int, int);
|
||||
constexpr Tup t(42, 101, -1);
|
||||
static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, "");
|
||||
static_assert(std::apply(sum_obj, t) == 142, "");
|
||||
}
|
||||
{
|
||||
using Tup = std::array<int, 3>;
|
||||
using Fn = int(&)(int, int, int);
|
||||
constexpr Tup t = {42, 101, -1};
|
||||
static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, "");
|
||||
static_assert(std::apply(sum_obj, t) == 142, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum CallQuals {
|
||||
CQ_None,
|
||||
CQ_LValue,
|
||||
CQ_ConstLValue,
|
||||
CQ_RValue,
|
||||
CQ_ConstRValue
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
struct CallInfo {
|
||||
CallQuals quals;
|
||||
TypeID const* arg_types;
|
||||
Tuple args;
|
||||
|
||||
template <class ...Args>
|
||||
CallInfo(CallQuals q, Args&&... xargs)
|
||||
: quals(q), arg_types(&makeArgumentID<Args&&...>()), args(std::forward<Args>(xargs)...)
|
||||
{}
|
||||
};
|
||||
|
||||
template <class ...Args>
|
||||
inline CallInfo<decltype(std::forward_as_tuple(std::declval<Args>()...))>
|
||||
makeCallInfo(CallQuals quals, Args&&... args) {
|
||||
return {quals, std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
struct TrackedCallable {
|
||||
|
||||
TrackedCallable() = default;
|
||||
|
||||
template <class ...Args> auto operator()(Args&&... xargs) &
|
||||
{ return makeCallInfo(CQ_LValue, std::forward<Args>(xargs)...); }
|
||||
|
||||
template <class ...Args> auto operator()(Args&&... xargs) const&
|
||||
{ return makeCallInfo(CQ_ConstLValue, std::forward<Args>(xargs)...); }
|
||||
|
||||
template <class ...Args> auto operator()(Args&&... xargs) &&
|
||||
{ return makeCallInfo(CQ_RValue, std::forward<Args>(xargs)...); }
|
||||
|
||||
template <class ...Args> auto operator()(Args&&... xargs) const&&
|
||||
{ return makeCallInfo(CQ_ConstRValue, std::forward<Args>(xargs)...); }
|
||||
};
|
||||
|
||||
template <class ...ExpectArgs, class Tuple>
|
||||
void check_apply_quals_and_types(Tuple&& t) {
|
||||
TypeID const* const expect_args = &makeArgumentID<ExpectArgs...>();
|
||||
TrackedCallable obj;
|
||||
TrackedCallable const& cobj = obj;
|
||||
{
|
||||
auto ret = std::apply(obj, std::forward<Tuple>(t));
|
||||
assert(ret.quals == CQ_LValue);
|
||||
assert(ret.arg_types == expect_args);
|
||||
assert(ret.args == t);
|
||||
}
|
||||
{
|
||||
auto ret = std::apply(cobj, std::forward<Tuple>(t));
|
||||
assert(ret.quals == CQ_ConstLValue);
|
||||
assert(ret.arg_types == expect_args);
|
||||
assert(ret.args == t);
|
||||
}
|
||||
{
|
||||
auto ret = std::apply(std::move(obj), std::forward<Tuple>(t));
|
||||
assert(ret.quals == CQ_RValue);
|
||||
assert(ret.arg_types == expect_args);
|
||||
assert(ret.args == t);
|
||||
}
|
||||
{
|
||||
auto ret = std::apply(std::move(cobj), std::forward<Tuple>(t));
|
||||
assert(ret.quals == CQ_ConstRValue);
|
||||
assert(ret.arg_types == expect_args);
|
||||
assert(ret.args == t);
|
||||
}
|
||||
}
|
||||
|
||||
void test_call_quals_and_arg_types()
|
||||
{
|
||||
TrackedCallable obj;
|
||||
using Tup = std::tuple<int, int const&, unsigned&&>;
|
||||
const int x = 42;
|
||||
unsigned y = 101;
|
||||
Tup t(-1, x, std::move(y));
|
||||
Tup const& ct = t;
|
||||
check_apply_quals_and_types<int&, int const&, unsigned&>(t);
|
||||
check_apply_quals_and_types<int const&, int const&, unsigned&>(ct);
|
||||
check_apply_quals_and_types<int&&, int const&, unsigned&&>(std::move(t));
|
||||
check_apply_quals_and_types<int const&&, int const&, unsigned&&>(std::move(ct));
|
||||
}
|
||||
|
||||
|
||||
struct NothrowMoveable {
|
||||
NothrowMoveable() noexcept = default;
|
||||
NothrowMoveable(NothrowMoveable const&) noexcept(false) {}
|
||||
NothrowMoveable(NothrowMoveable&&) noexcept {}
|
||||
};
|
||||
|
||||
template <bool IsNoexcept>
|
||||
struct TestNoexceptCallable {
|
||||
template <class ...Args>
|
||||
NothrowMoveable operator()(Args...) const noexcept(IsNoexcept) { return {}; }
|
||||
};
|
||||
|
||||
void test_noexcept()
|
||||
{
|
||||
TestNoexceptCallable<true> nec;
|
||||
TestNoexceptCallable<false> tc;
|
||||
{
|
||||
// test that the functions noexcept-ness is propagated
|
||||
using Tup = std::tuple<int, const char*, long>;
|
||||
Tup t;
|
||||
ASSERT_NOEXCEPT(std::apply(nec, t));
|
||||
ASSERT_NOT_NOEXCEPT(std::apply(tc, t));
|
||||
}
|
||||
{
|
||||
// test that the noexcept-ness of the argument conversions is checked.
|
||||
using Tup = std::tuple<NothrowMoveable, int>;
|
||||
Tup t;
|
||||
ASSERT_NOT_NOEXCEPT(std::apply(nec, t));
|
||||
ASSERT_NOEXCEPT(std::apply(nec, std::move(t)));
|
||||
}
|
||||
}
|
||||
|
||||
namespace ReturnTypeTest {
|
||||
static int my_int = 42;
|
||||
|
||||
template <int N> struct index {};
|
||||
|
||||
void f(index<0>) {}
|
||||
|
||||
int f(index<1>) { return 0; }
|
||||
|
||||
int & f(index<2>) { return static_cast<int &>(my_int); }
|
||||
int const & f(index<3>) { return static_cast<int const &>(my_int); }
|
||||
int volatile & f(index<4>) { return static_cast<int volatile &>(my_int); }
|
||||
int const volatile & f(index<5>) { return static_cast<int const volatile &>(my_int); }
|
||||
|
||||
int && f(index<6>) { return static_cast<int &&>(my_int); }
|
||||
int const && f(index<7>) { return static_cast<int const &&>(my_int); }
|
||||
int volatile && f(index<8>) { return static_cast<int volatile &&>(my_int); }
|
||||
int const volatile && f(index<9>) { return static_cast<int const volatile &&>(my_int); }
|
||||
|
||||
int * f(index<10>) { return static_cast<int *>(&my_int); }
|
||||
int const * f(index<11>) { return static_cast<int const *>(&my_int); }
|
||||
int volatile * f(index<12>) { return static_cast<int volatile *>(&my_int); }
|
||||
int const volatile * f(index<13>) { return static_cast<int const volatile *>(&my_int); }
|
||||
|
||||
template <int Func, class Expect>
|
||||
void test()
|
||||
{
|
||||
using RawInvokeResult = decltype(f(index<Func>{}));
|
||||
static_assert(std::is_same<RawInvokeResult, Expect>::value, "");
|
||||
using FnType = RawInvokeResult (*) (index<Func>);
|
||||
FnType fn = f;
|
||||
std::tuple<index<Func>> t; ((void)t);
|
||||
using InvokeResult = decltype(std::apply(fn, t));
|
||||
static_assert(std::is_same<InvokeResult, Expect>::value, "");
|
||||
}
|
||||
} // end namespace ReturnTypeTest
|
||||
|
||||
void test_return_type()
|
||||
{
|
||||
using ReturnTypeTest::test;
|
||||
test<0, void>();
|
||||
test<1, int>();
|
||||
test<2, int &>();
|
||||
test<3, int const &>();
|
||||
test<4, int volatile &>();
|
||||
test<5, int const volatile &>();
|
||||
test<6, int &&>();
|
||||
test<7, int const &&>();
|
||||
test<8, int volatile &&>();
|
||||
test<9, int const volatile &&>();
|
||||
test<10, int *>();
|
||||
test<11, int const *>();
|
||||
test<12, int volatile *>();
|
||||
test<13, int const volatile *>();
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_constexpr_evaluation();
|
||||
test_call_quals_and_arg_types();
|
||||
test_return_type();
|
||||
test_noexcept();
|
||||
}
|
|
@ -0,0 +1,426 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
|
||||
|
||||
// Testing extended function types. The extended function types are those
|
||||
// named by INVOKE but that are not actual callable objects. These include
|
||||
// bullets 1-4 of invoke.
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
|
||||
// std::array is explicitly allowed to be initialized with A a = { init-list };.
|
||||
// Disable the missing braces warning for this reason.
|
||||
#include "disable_missing_braces_warning.h"
|
||||
|
||||
int count = 0;
|
||||
|
||||
struct A_int_0
|
||||
{
|
||||
A_int_0() : obj1(0){}
|
||||
A_int_0(int x) : obj1(x) {}
|
||||
int mem1() { return ++count; }
|
||||
int mem2() const { return ++count; }
|
||||
int const obj1;
|
||||
};
|
||||
|
||||
struct A_int_1
|
||||
{
|
||||
A_int_1() {}
|
||||
A_int_1(int) {}
|
||||
int mem1(int x) { return count += x; }
|
||||
int mem2(int x) const { return count += x; }
|
||||
};
|
||||
|
||||
struct A_int_2
|
||||
{
|
||||
A_int_2() {}
|
||||
A_int_2(int) {}
|
||||
int mem1(int x, int y) { return count += (x + y); }
|
||||
int mem2(int x, int y) const { return count += (x + y); }
|
||||
};
|
||||
|
||||
template <class A>
|
||||
struct A_wrap
|
||||
{
|
||||
A_wrap() {}
|
||||
A_wrap(int x) : m_a(x) {}
|
||||
A & operator*() { return m_a; }
|
||||
A const & operator*() const { return m_a; }
|
||||
A m_a;
|
||||
};
|
||||
|
||||
typedef A_wrap<A_int_0> A_wrap_0;
|
||||
typedef A_wrap<A_int_1> A_wrap_1;
|
||||
typedef A_wrap<A_int_2> A_wrap_2;
|
||||
|
||||
|
||||
template <class A>
|
||||
struct A_base : public A
|
||||
{
|
||||
A_base() : A() {}
|
||||
A_base(int x) : A(x) {}
|
||||
};
|
||||
|
||||
typedef A_base<A_int_0> A_base_0;
|
||||
typedef A_base<A_int_1> A_base_1;
|
||||
typedef A_base<A_int_2> A_base_2;
|
||||
|
||||
|
||||
template <
|
||||
class Tuple, class ConstTuple
|
||||
, class TuplePtr, class ConstTuplePtr
|
||||
, class TupleWrap, class ConstTupleWrap
|
||||
, class TupleBase, class ConstTupleBase
|
||||
>
|
||||
void test_ext_int_0()
|
||||
{
|
||||
count = 0;
|
||||
typedef A_int_0 T;
|
||||
typedef A_wrap_0 Wrap;
|
||||
typedef A_base_0 Base;
|
||||
|
||||
typedef int(T::*mem1_t)();
|
||||
mem1_t mem1 = &T::mem1;
|
||||
|
||||
typedef int(T::*mem2_t)() const;
|
||||
mem2_t mem2 = &T::mem2;
|
||||
|
||||
typedef int const T::*obj1_t;
|
||||
obj1_t obj1 = &T::obj1;
|
||||
|
||||
// member function w/ref
|
||||
{
|
||||
T a;
|
||||
Tuple t{a};
|
||||
assert(1 == std::apply(mem1, t));
|
||||
assert(count == 1);
|
||||
}
|
||||
count = 0;
|
||||
// member function w/pointer
|
||||
{
|
||||
T a;
|
||||
TuplePtr t{&a};
|
||||
assert(1 == std::apply(mem1, t));
|
||||
assert(count == 1);
|
||||
}
|
||||
count = 0;
|
||||
// member function w/base
|
||||
{
|
||||
Base a;
|
||||
TupleBase t{a};
|
||||
assert(1 == std::apply(mem1, t));
|
||||
assert(count == 1);
|
||||
}
|
||||
count = 0;
|
||||
// member function w/wrap
|
||||
{
|
||||
Wrap a;
|
||||
TupleWrap t{a};
|
||||
assert(1 == std::apply(mem1, t));
|
||||
assert(count == 1);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/ref
|
||||
{
|
||||
T const a;
|
||||
ConstTuple t{a};
|
||||
assert(1 == std::apply(mem2, t));
|
||||
assert(count == 1);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/pointer
|
||||
{
|
||||
T const a;
|
||||
ConstTuplePtr t{&a};
|
||||
assert(1 == std::apply(mem2, t));
|
||||
assert(count == 1);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/base
|
||||
{
|
||||
Base const a;
|
||||
ConstTupleBase t{a};
|
||||
assert(1 == std::apply(mem2, t));
|
||||
assert(count == 1);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/wrapper
|
||||
{
|
||||
Wrap const a;
|
||||
ConstTupleWrap t{a};
|
||||
assert(1 == std::apply(mem2, t));
|
||||
assert(1 == count);
|
||||
}
|
||||
// member object w/ref
|
||||
{
|
||||
T a{42};
|
||||
Tuple t{a};
|
||||
assert(42 == std::apply(obj1, t));
|
||||
}
|
||||
// member object w/pointer
|
||||
{
|
||||
T a{42};
|
||||
TuplePtr t{&a};
|
||||
assert(42 == std::apply(obj1, t));
|
||||
}
|
||||
// member object w/base
|
||||
{
|
||||
Base a{42};
|
||||
TupleBase t{a};
|
||||
assert(42 == std::apply(obj1, t));
|
||||
}
|
||||
// member object w/wrapper
|
||||
{
|
||||
Wrap a{42};
|
||||
TupleWrap t{a};
|
||||
assert(42 == std::apply(obj1, t));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
class Tuple, class ConstTuple
|
||||
, class TuplePtr, class ConstTuplePtr
|
||||
, class TupleWrap, class ConstTupleWrap
|
||||
, class TupleBase, class ConstTupleBase
|
||||
>
|
||||
void test_ext_int_1()
|
||||
{
|
||||
count = 0;
|
||||
typedef A_int_1 T;
|
||||
typedef A_wrap_1 Wrap;
|
||||
typedef A_base_1 Base;
|
||||
|
||||
typedef int(T::*mem1_t)(int);
|
||||
mem1_t mem1 = &T::mem1;
|
||||
|
||||
typedef int(T::*mem2_t)(int) const;
|
||||
mem2_t mem2 = &T::mem2;
|
||||
|
||||
// member function w/ref
|
||||
{
|
||||
T a;
|
||||
Tuple t{a, 2};
|
||||
assert(2 == std::apply(mem1, t));
|
||||
assert(count == 2);
|
||||
}
|
||||
count = 0;
|
||||
// member function w/pointer
|
||||
{
|
||||
T a;
|
||||
TuplePtr t{&a, 3};
|
||||
assert(3 == std::apply(mem1, t));
|
||||
assert(count == 3);
|
||||
}
|
||||
count = 0;
|
||||
// member function w/base
|
||||
{
|
||||
Base a;
|
||||
TupleBase t{a, 4};
|
||||
assert(4 == std::apply(mem1, t));
|
||||
assert(count == 4);
|
||||
}
|
||||
count = 0;
|
||||
// member function w/wrap
|
||||
{
|
||||
Wrap a;
|
||||
TupleWrap t{a, 5};
|
||||
assert(5 == std::apply(mem1, t));
|
||||
assert(count == 5);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/ref
|
||||
{
|
||||
T const a;
|
||||
ConstTuple t{a, 6};
|
||||
assert(6 == std::apply(mem2, t));
|
||||
assert(count == 6);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/pointer
|
||||
{
|
||||
T const a;
|
||||
ConstTuplePtr t{&a, 7};
|
||||
assert(7 == std::apply(mem2, t));
|
||||
assert(count == 7);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/base
|
||||
{
|
||||
Base const a;
|
||||
ConstTupleBase t{a, 8};
|
||||
assert(8 == std::apply(mem2, t));
|
||||
assert(count == 8);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/wrapper
|
||||
{
|
||||
Wrap const a;
|
||||
ConstTupleWrap t{a, 9};
|
||||
assert(9 == std::apply(mem2, t));
|
||||
assert(9 == count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
class Tuple, class ConstTuple
|
||||
, class TuplePtr, class ConstTuplePtr
|
||||
, class TupleWrap, class ConstTupleWrap
|
||||
, class TupleBase, class ConstTupleBase
|
||||
>
|
||||
void test_ext_int_2()
|
||||
{
|
||||
count = 0;
|
||||
typedef A_int_2 T;
|
||||
typedef A_wrap_2 Wrap;
|
||||
typedef A_base_2 Base;
|
||||
|
||||
typedef int(T::*mem1_t)(int, int);
|
||||
mem1_t mem1 = &T::mem1;
|
||||
|
||||
typedef int(T::*mem2_t)(int, int) const;
|
||||
mem2_t mem2 = &T::mem2;
|
||||
|
||||
// member function w/ref
|
||||
{
|
||||
T a;
|
||||
Tuple t{a, 1, 1};
|
||||
assert(2 == std::apply(mem1, t));
|
||||
assert(count == 2);
|
||||
}
|
||||
count = 0;
|
||||
// member function w/pointer
|
||||
{
|
||||
T a;
|
||||
TuplePtr t{&a, 1, 2};
|
||||
assert(3 == std::apply(mem1, t));
|
||||
assert(count == 3);
|
||||
}
|
||||
count = 0;
|
||||
// member function w/base
|
||||
{
|
||||
Base a;
|
||||
TupleBase t{a, 2, 2};
|
||||
assert(4 == std::apply(mem1, t));
|
||||
assert(count == 4);
|
||||
}
|
||||
count = 0;
|
||||
// member function w/wrap
|
||||
{
|
||||
Wrap a;
|
||||
TupleWrap t{a, 2, 3};
|
||||
assert(5 == std::apply(mem1, t));
|
||||
assert(count == 5);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/ref
|
||||
{
|
||||
T const a;
|
||||
ConstTuple t{a, 3, 3};
|
||||
assert(6 == std::apply(mem2, t));
|
||||
assert(count == 6);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/pointer
|
||||
{
|
||||
T const a;
|
||||
ConstTuplePtr t{&a, 3, 4};
|
||||
assert(7 == std::apply(mem2, t));
|
||||
assert(count == 7);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/base
|
||||
{
|
||||
Base const a;
|
||||
ConstTupleBase t{a, 4, 4};
|
||||
assert(8 == std::apply(mem2, t));
|
||||
assert(count == 8);
|
||||
}
|
||||
count = 0;
|
||||
// const member function w/wrapper
|
||||
{
|
||||
Wrap const a;
|
||||
ConstTupleWrap t{a, 4, 5};
|
||||
assert(9 == std::apply(mem2, t));
|
||||
assert(9 == count);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
test_ext_int_0<
|
||||
std::tuple<A_int_0 &>, std::tuple<A_int_0 const &>
|
||||
, std::tuple<A_int_0 *>, std::tuple<A_int_0 const *>
|
||||
, std::tuple<A_wrap_0 &>, std::tuple<A_wrap_0 const &>
|
||||
, std::tuple<A_base_0 &>, std::tuple<A_base_0 const &>
|
||||
>();
|
||||
test_ext_int_0<
|
||||
std::tuple<A_int_0>, std::tuple<A_int_0 const>
|
||||
, std::tuple<A_int_0 *>, std::tuple<A_int_0 const *>
|
||||
, std::tuple<A_wrap_0>, std::tuple<A_wrap_0 const>
|
||||
, std::tuple<A_base_0>, std::tuple<A_base_0 const>
|
||||
>();
|
||||
test_ext_int_0<
|
||||
std::array<A_int_0, 1>, std::array<A_int_0 const, 1>
|
||||
, std::array<A_int_0*, 1>, std::array<A_int_0 const*, 1>
|
||||
, std::array<A_wrap_0, 1>, std::array<A_wrap_0 const, 1>
|
||||
, std::array<A_base_0, 1>, std::array<A_base_0 const, 1>
|
||||
>();
|
||||
}
|
||||
{
|
||||
test_ext_int_1<
|
||||
std::tuple<A_int_1 &, int>, std::tuple<A_int_1 const &, int>
|
||||
, std::tuple<A_int_1 *, int>, std::tuple<A_int_1 const *, int>
|
||||
, std::tuple<A_wrap_1 &, int>, std::tuple<A_wrap_1 const &, int>
|
||||
, std::tuple<A_base_1 &, int>, std::tuple<A_base_1 const &, int>
|
||||
>();
|
||||
test_ext_int_1<
|
||||
std::tuple<A_int_1, int>, std::tuple<A_int_1 const, int>
|
||||
, std::tuple<A_int_1 *, int>, std::tuple<A_int_1 const *, int>
|
||||
, std::tuple<A_wrap_1, int>, std::tuple<A_wrap_1 const, int>
|
||||
, std::tuple<A_base_1, int>, std::tuple<A_base_1 const, int>
|
||||
>();
|
||||
test_ext_int_1<
|
||||
std::pair<A_int_1 &, int>, std::pair<A_int_1 const &, int>
|
||||
, std::pair<A_int_1 *, int>, std::pair<A_int_1 const *, int>
|
||||
, std::pair<A_wrap_1 &, int>, std::pair<A_wrap_1 const &, int>
|
||||
, std::pair<A_base_1 &, int>, std::pair<A_base_1 const &, int>
|
||||
>();
|
||||
test_ext_int_1<
|
||||
std::pair<A_int_1, int>, std::pair<A_int_1 const, int>
|
||||
, std::pair<A_int_1 *, int>, std::pair<A_int_1 const *, int>
|
||||
, std::pair<A_wrap_1, int>, std::pair<A_wrap_1 const, int>
|
||||
, std::pair<A_base_1, int>, std::pair<A_base_1 const, int>
|
||||
>();
|
||||
}
|
||||
{
|
||||
test_ext_int_2<
|
||||
std::tuple<A_int_2 &, int, int>, std::tuple<A_int_2 const &, int, int>
|
||||
, std::tuple<A_int_2 *, int, int>, std::tuple<A_int_2 const *, int, int>
|
||||
, std::tuple<A_wrap_2 &, int, int>, std::tuple<A_wrap_2 const &, int, int>
|
||||
, std::tuple<A_base_2 &, int, int>, std::tuple<A_base_2 const &, int, int>
|
||||
>();
|
||||
test_ext_int_2<
|
||||
std::tuple<A_int_2, int, int>, std::tuple<A_int_2 const, int, int>
|
||||
, std::tuple<A_int_2 *, int, int>, std::tuple<A_int_2 const *, int, int>
|
||||
, std::tuple<A_wrap_2, int, int>, std::tuple<A_wrap_2 const, int, int>
|
||||
, std::tuple<A_base_2, int, int>, std::tuple<A_base_2 const, int, int>
|
||||
>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
|
||||
|
||||
// Stress testing large arities with tuple and array.
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class T, std::size_t Dummy = 0>
|
||||
struct always_imp
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T, std::size_t Dummy = 0>
|
||||
using always_t = typename always_imp<T, Dummy>::type;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class Tuple, class Idx>
|
||||
struct make_function;
|
||||
|
||||
template <class Tp, std::size_t ...Idx>
|
||||
struct make_function<Tp, std::integer_sequence<std::size_t, Idx...>>
|
||||
{
|
||||
using type = bool (*)(always_t<Tp, Idx>...);
|
||||
};
|
||||
|
||||
template <class Tp, std::size_t Size>
|
||||
using make_function_t = typename make_function<Tp, std::make_index_sequence<Size>>::type;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class Tp, class Idx>
|
||||
struct make_tuple_imp;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class Tp, std::size_t ...Idx>
|
||||
struct make_tuple_imp<Tp, std::integer_sequence<std::size_t, Idx...>>
|
||||
{
|
||||
using type = std::tuple<always_t<Tp, Idx>...>;
|
||||
};
|
||||
|
||||
template <class Tp, std::size_t Size>
|
||||
using make_tuple_t = typename make_tuple_imp<Tp, std::make_index_sequence<Size>>::type;
|
||||
|
||||
template <class ...Types>
|
||||
bool test_apply_fn(Types...) { return true; }
|
||||
|
||||
|
||||
template <std::size_t Size>
|
||||
void test_all()
|
||||
{
|
||||
|
||||
using A = std::array<int, Size>;
|
||||
using ConstA = std::array<int const, Size>;
|
||||
|
||||
using Tuple = make_tuple_t<int, Size>;
|
||||
using CTuple = make_tuple_t<const int, Size>;
|
||||
|
||||
using ValFn = make_function_t<int, Size>;
|
||||
ValFn val_fn = &test_apply_fn;
|
||||
|
||||
using RefFn = make_function_t<int &, Size>;
|
||||
RefFn ref_fn = &test_apply_fn;
|
||||
|
||||
using CRefFn = make_function_t<int const &, Size>;
|
||||
CRefFn cref_fn = &test_apply_fn;
|
||||
|
||||
using RRefFn = make_function_t<int &&, Size>;
|
||||
RRefFn rref_fn = &test_apply_fn;
|
||||
|
||||
{
|
||||
A a{};
|
||||
assert(std::apply(val_fn, a));
|
||||
assert(std::apply(ref_fn, a));
|
||||
assert(std::apply(cref_fn, a));
|
||||
assert(std::apply(rref_fn, std::move(a)));
|
||||
}
|
||||
{
|
||||
ConstA a{};
|
||||
assert(std::apply(val_fn, a));
|
||||
assert(std::apply(cref_fn, a));
|
||||
}
|
||||
{
|
||||
Tuple a{};
|
||||
assert(std::apply(val_fn, a));
|
||||
assert(std::apply(ref_fn, a));
|
||||
assert(std::apply(cref_fn, a));
|
||||
assert(std::apply(rref_fn, std::move(a)));
|
||||
}
|
||||
{
|
||||
CTuple a{};
|
||||
assert(std::apply(val_fn, a));
|
||||
assert(std::apply(cref_fn, a));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <std::size_t Size>
|
||||
void test_one()
|
||||
{
|
||||
using A = std::array<int, Size>;
|
||||
using Tuple = make_tuple_t<int, Size>;
|
||||
|
||||
using ValFn = make_function_t<int, Size>;
|
||||
ValFn val_fn = &test_apply_fn;
|
||||
|
||||
{
|
||||
A a{};
|
||||
assert(std::apply(val_fn, a));
|
||||
}
|
||||
{
|
||||
Tuple a{};
|
||||
assert(std::apply(val_fn, a));
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Instantiate with 1-5 arguments.
|
||||
test_all<1>();
|
||||
test_all<2>();
|
||||
test_all<3>();
|
||||
test_all<4>();
|
||||
test_all<5>();
|
||||
|
||||
// Stress test with 256
|
||||
test_one<256>();
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class T, class Tuple> constexpr T make_from_tuple(Tuple&&);
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "type_id.h"
|
||||
|
||||
template <class Tuple>
|
||||
struct ConstexprConstructibleFromTuple {
|
||||
template <class ...Args>
|
||||
explicit constexpr ConstexprConstructibleFromTuple(Args&&... xargs)
|
||||
: args{std::forward<Args>(xargs)...} {}
|
||||
Tuple args;
|
||||
};
|
||||
|
||||
template <class TupleLike>
|
||||
struct ConstructibleFromTuple;
|
||||
|
||||
template <template <class ...> class Tuple, class ...Types>
|
||||
struct ConstructibleFromTuple<Tuple<Types...>> {
|
||||
template <class ...Args>
|
||||
explicit ConstructibleFromTuple(Args&&... xargs)
|
||||
: args(xargs...),
|
||||
arg_types(&makeArgumentID<Args&&...>())
|
||||
{}
|
||||
Tuple<std::decay_t<Types>...> args;
|
||||
TypeID const* arg_types;
|
||||
};
|
||||
|
||||
template <class Tp, size_t N>
|
||||
struct ConstructibleFromTuple<std::array<Tp, N>> {
|
||||
template <class ...Args>
|
||||
explicit ConstructibleFromTuple(Args&&... xargs)
|
||||
: args{xargs...},
|
||||
arg_types(&makeArgumentID<Args&&...>())
|
||||
{}
|
||||
std::array<Tp, N> args;
|
||||
TypeID const* arg_types;
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
constexpr bool do_constexpr_test(Tuple&& tup) {
|
||||
using RawTuple = std::decay_t<Tuple>;
|
||||
using Tp = ConstexprConstructibleFromTuple<RawTuple>;
|
||||
return std::make_from_tuple<Tp>(std::forward<Tuple>(tup)).args == tup;
|
||||
}
|
||||
|
||||
// Needed by do_forwarding_test() since it compare pairs of different types.
|
||||
template <class T1, class T2, class U1, class U2>
|
||||
inline bool operator==(const std::pair<T1, T2>& lhs, const std::pair<U1, U2>& rhs) {
|
||||
return lhs.first == rhs.first && lhs.second == rhs.second;
|
||||
}
|
||||
|
||||
template <class ...ExpectTypes, class Tuple>
|
||||
bool do_forwarding_test(Tuple&& tup) {
|
||||
using RawTuple = std::decay_t<Tuple>;
|
||||
using Tp = ConstructibleFromTuple<RawTuple>;
|
||||
const Tp value = std::make_from_tuple<Tp>(std::forward<Tuple>(tup));
|
||||
return value.args == tup
|
||||
&& value.arg_types == &makeArgumentID<ExpectTypes...>();
|
||||
}
|
||||
|
||||
void test_constexpr_construction() {
|
||||
{
|
||||
constexpr std::tuple<> tup;
|
||||
static_assert(do_constexpr_test(tup), "");
|
||||
}
|
||||
{
|
||||
constexpr std::tuple<int> tup(42);
|
||||
static_assert(do_constexpr_test(tup), "");
|
||||
}
|
||||
{
|
||||
constexpr std::tuple<int, long, void*> tup(42, 101, nullptr);
|
||||
static_assert(do_constexpr_test(tup), "");
|
||||
}
|
||||
{
|
||||
constexpr std::pair<int, const char*> p(42, "hello world");
|
||||
static_assert(do_constexpr_test(p), "");
|
||||
}
|
||||
{
|
||||
using Tuple = std::array<int, 3>;
|
||||
using ValueTp = ConstexprConstructibleFromTuple<Tuple>;
|
||||
constexpr Tuple arr = {42, 101, -1};
|
||||
constexpr ValueTp value = std::make_from_tuple<ValueTp>(arr);
|
||||
static_assert(value.args[0] == arr[0] && value.args[1] == arr[1]
|
||||
&& value.args[2] == arr[2], "");
|
||||
}
|
||||
}
|
||||
|
||||
void test_perfect_forwarding() {
|
||||
{
|
||||
using Tup = std::tuple<>;
|
||||
Tup tup;
|
||||
Tup const& ctup = tup;
|
||||
assert(do_forwarding_test<>(tup));
|
||||
assert(do_forwarding_test<>(ctup));
|
||||
}
|
||||
{
|
||||
using Tup = std::tuple<int>;
|
||||
Tup tup(42);
|
||||
Tup const& ctup = tup;
|
||||
assert(do_forwarding_test<int&>(tup));
|
||||
assert(do_forwarding_test<int const&>(ctup));
|
||||
assert(do_forwarding_test<int&&>(std::move(tup)));
|
||||
assert(do_forwarding_test<int const&&>(std::move(ctup)));
|
||||
}
|
||||
{
|
||||
using Tup = std::tuple<int&, const char*, unsigned&&>;
|
||||
int x = 42;
|
||||
unsigned y = 101;
|
||||
Tup tup(x, "hello world", std::move(y));
|
||||
Tup const& ctup = tup;
|
||||
assert((do_forwarding_test<int&, const char*&, unsigned&>(tup)));
|
||||
assert((do_forwarding_test<int&, const char* const&, unsigned &>(ctup)));
|
||||
assert((do_forwarding_test<int&, const char*&&, unsigned&&>(std::move(tup))));
|
||||
assert((do_forwarding_test<int&, const char* const&&, unsigned &&>(std::move(ctup))));
|
||||
}
|
||||
// test with pair<T, U>
|
||||
{
|
||||
using Tup = std::pair<int&, const char*>;
|
||||
int x = 42;
|
||||
Tup tup(x, "hello world");
|
||||
Tup const& ctup = tup;
|
||||
assert((do_forwarding_test<int&, const char*&>(tup)));
|
||||
assert((do_forwarding_test<int&, const char* const&>(ctup)));
|
||||
assert((do_forwarding_test<int&, const char*&&>(std::move(tup))));
|
||||
assert((do_forwarding_test<int&, const char* const&&>(std::move(ctup))));
|
||||
}
|
||||
// test with array<T, I>
|
||||
{
|
||||
using Tup = std::array<int, 3>;
|
||||
Tup tup = {42, 101, -1};
|
||||
Tup const& ctup = tup;
|
||||
assert((do_forwarding_test<int&, int&, int&>(tup)));
|
||||
assert((do_forwarding_test<int const&, int const&, int const&>(ctup)));
|
||||
assert((do_forwarding_test<int&&, int&&, int&&>(std::move(tup))));
|
||||
assert((do_forwarding_test<int const&&, int const&&, int const&&>(std::move(ctup))));
|
||||
}
|
||||
}
|
||||
|
||||
void test_noexcept() {
|
||||
struct NothrowMoveable {
|
||||
NothrowMoveable() = default;
|
||||
NothrowMoveable(NothrowMoveable const&) {}
|
||||
NothrowMoveable(NothrowMoveable&&) noexcept {}
|
||||
};
|
||||
struct TestType {
|
||||
TestType(int, NothrowMoveable) noexcept {}
|
||||
TestType(int, int, int) noexcept(false) {}
|
||||
TestType(long, long, long) noexcept {}
|
||||
};
|
||||
{
|
||||
using Tuple = std::tuple<int, NothrowMoveable>;
|
||||
Tuple tup; ((void)tup);
|
||||
Tuple const& ctup = tup; ((void)ctup);
|
||||
ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
|
||||
ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
|
||||
}
|
||||
{
|
||||
using Tuple = std::pair<int, NothrowMoveable>;
|
||||
Tuple tup; ((void)tup);
|
||||
Tuple const& ctup = tup; ((void)ctup);
|
||||
ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
|
||||
ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
|
||||
}
|
||||
{
|
||||
using Tuple = std::tuple<int, int, int>;
|
||||
Tuple tup; ((void)tup);
|
||||
ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
|
||||
}
|
||||
{
|
||||
using Tuple = std::tuple<long, long, long>;
|
||||
Tuple tup; ((void)tup);
|
||||
ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
|
||||
}
|
||||
{
|
||||
using Tuple = std::array<int, 3>;
|
||||
Tuple tup; ((void)tup);
|
||||
ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
|
||||
}
|
||||
{
|
||||
using Tuple = std::array<long, 3>;
|
||||
Tuple tup; ((void)tup);
|
||||
ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_constexpr_construction();
|
||||
test_perfect_forwarding();
|
||||
test_noexcept();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class... Types>
|
||||
// class tuple_size<tuple<Types...>>
|
||||
// : public integral_constant<size_t, sizeof...(Types)> { };
|
||||
|
||||
// Expect failures with a reference type, pointer type, and a non-tuple type.
|
||||
|
||||
#include <tuple>
|
||||
|
||||
int main()
|
||||
{
|
||||
(void)std::tuple_size<std::tuple<> &>::value; // expected-error {{implicit instantiation of undefined template}}
|
||||
(void)std::tuple_size<int>::value; // expected-error {{implicit instantiation of undefined template}}
|
||||
(void)std::tuple_size<std::tuple<>*>::value; // expected-error {{implicit instantiation of undefined template}}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class T> constexpr size_t tuple_size_v = tuple_size<T>::value;
|
||||
|
||||
// Expect failures with a reference type, pointer type, and a non-tuple type.
|
||||
|
||||
#include <tuple>
|
||||
|
||||
int main()
|
||||
{
|
||||
(void)std::tuple_size_v<std::tuple<> &>; // expected-note {{requested here}}
|
||||
(void)std::tuple_size_v<int>; // expected-note {{requested here}}
|
||||
(void)std::tuple_size_v<std::tuple<>*>; // expected-note {{requested here}}
|
||||
// expected-error@tuple:* 3 {{implicit instantiation of undefined template}}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <tuple>
|
||||
|
||||
// template <class T> constexpr size_t tuple_size_v = tuple_size<T>::value;
|
||||
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <array>
|
||||
|
||||
template <class Tuple, int Expect>
|
||||
void test()
|
||||
{
|
||||
static_assert(std::tuple_size_v<Tuple> == Expect, "");
|
||||
static_assert(std::tuple_size_v<Tuple> == std::tuple_size<Tuple>::value, "");
|
||||
static_assert(std::tuple_size_v<Tuple const> == std::tuple_size<Tuple>::value, "");
|
||||
static_assert(std::tuple_size_v<Tuple volatile> == std::tuple_size<Tuple>::value, "");
|
||||
static_assert(std::tuple_size_v<Tuple const volatile> == std::tuple_size<Tuple>::value, "");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test<std::tuple<>, 0>();
|
||||
|
||||
test<std::tuple<int>, 1>();
|
||||
test<std::array<int, 1>, 1>();
|
||||
|
||||
test<std::tuple<int, int>, 2>();
|
||||
test<std::pair<int, int>, 2>();
|
||||
test<std::array<int, 2>, 2>();
|
||||
|
||||
test<std::tuple<int, int, int>, 3>();
|
||||
test<std::array<int, 3>, 3>();
|
||||
}
|
|
@ -106,7 +106,7 @@
|
|||
<tr><td><a href="http://wg21.link/p0175r1">p0175r1</a></td><td>LWG</td><td>Synopses for the C library</td><td>Oulu</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/p0180r2">p0180r2</a></td><td>LWG</td><td>Reserve a New Library Namespace for Future Standardization</td><td>Oulu</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/p0181r1">p0181r1</a></td><td>LWG</td><td>Ordered by Default</td><td>Oulu</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/p0209r2">p0209r2</a></td><td>LWG</td><td>make_from_tuple: apply for construction</td><td>Oulu</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/p0209r2">p0209r2</a></td><td>LWG</td><td>make_from_tuple: apply for construction</td><td>Oulu</td><td>Complete</td><td>3.9</td></tr>
|
||||
<tr><td><a href="http://wg21.link/p0219r1">p0219r1</a></td><td>LWG</td><td>Relative Paths for Filesystem</td><td>Oulu</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/p0254r2">p0254r2</a></td><td>LWG</td><td>Integrating std::string_view and std::string</td><td>Oulu</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/p0258r2">p0258r2</a></td><td>LWG</td><td>has_unique_object_representations</td><td>Oulu</td><td></td><td></td></tr>
|
||||
|
|
Loading…
Reference in New Issue