aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorDaniel Krugler <daniel.kruegler@googlemail.com>2011-09-11 22:10:21 +0000
committerPaolo Carlini <paolo@gcc.gnu.org>2011-09-11 22:10:21 +0000
commitac65b7d221231caa58b02a619da018dbbaa6a3e5 (patch)
treefc1dd8d8b32c5967145919371cb46e76351d1c2b /libstdc++-v3
parentfa11ae6c728fdde8746fc77107c3a1095ac88f59 (diff)
downloadgcc-ac65b7d221231caa58b02a619da018dbbaa6a3e5.zip
gcc-ac65b7d221231caa58b02a619da018dbbaa6a3e5.tar.gz
gcc-ac65b7d221231caa58b02a619da018dbbaa6a3e5.tar.bz2
re PR libstdc++/50159 ([C++0x] tuple_cat only accepts two arguments)
2011-09-11 Daniel Krugler <daniel.kruegler@googlemail.com> PR libstdc++/50159 * include/std/tuple (tuple_cat): Reimplement according to the resolution of LWG 1385. * include/std/type_traits: Define __and_ and __or_ for zero arguments too; minor tweaks. * testsuite/20_util/tuple/creation_functions/tuple_cat.cc: New. * testsuite/20_util/tuple/creation_functions/constexpr.cc: Disable for now tuple_cat test. * testsuite/20_util/declval/requirements/1_neg.cc: Adjust dg-error line numbers. * testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Likewise. * testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Likewise. * doc/xml/manual/status_cxx200x.xml: Update. From-SVN: r178770
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog17
-rw-r--r--libstdc++-v3/doc/xml/manual/status_cxx200x.xml5
-rw-r--r--libstdc++-v3/include/std/tuple277
-rw-r--r--libstdc++-v3/include/std/type_traits62
-rw-r--r--libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/creation_functions/constexpr.cc5
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/creation_functions/tuple_cat.cc131
9 files changed, 358 insertions, 149 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 64f7551..8edaae5 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,20 @@
+2011-09-11 Daniel Krugler <daniel.kruegler@googlemail.com>
+
+ PR libstdc++/50159
+ * include/std/tuple (tuple_cat): Reimplement according to the
+ resolution of LWG 1385.
+ * include/std/type_traits: Define __and_ and __or_ for zero
+ arguments too; minor tweaks.
+ * testsuite/20_util/tuple/creation_functions/tuple_cat.cc: New.
+ * testsuite/20_util/tuple/creation_functions/constexpr.cc: Disable
+ for now tuple_cat test.
+ * testsuite/20_util/declval/requirements/1_neg.cc: Adjust dg-error
+ line numbers.
+ * testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Likewise.
+ * testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc:
+ Likewise.
+ * doc/xml/manual/status_cxx200x.xml: Update.
+
2011-09-09 Paolo Carlini <paolo.carlini@oracle.com>
* include/std/tuple: Use everywhere std::size_t... instead of int...
diff --git a/libstdc++-v3/doc/xml/manual/status_cxx200x.xml b/libstdc++-v3/doc/xml/manual/status_cxx200x.xml
index 88e238f2..3922dff 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx200x.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx200x.xml
@@ -443,11 +443,10 @@ particular release.
<entry/>
</row>
<row>
- <?dbhtml bgcolor="#B0B0B0" ?>
<entry>20.4.2.4</entry>
<entry>Tuple creation functions</entry>
- <entry>Partial</entry>
- <entry><code>tuple_cat</code> should be a single variadic signature (DR 1385)</entry>
+ <entry>Y</entry>
+ <entry/>
</row>
<row>
<entry>20.4.2.5</entry>
diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index 515fb4ea..1b4a823 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -876,108 +876,184 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
forward_as_tuple(_Elements&&... __args) noexcept
{ return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); }
- template<std::size_t...> struct __index_holder { };
- template<std::size_t __i, typename _IdxHolder, typename... _Elements>
- struct __index_holder_impl;
+ template<typename, std::size_t> struct array;
- template<std::size_t __i, std::size_t... _Indexes, typename _IdxHolder,
- typename... _Elements>
- struct __index_holder_impl<__i, __index_holder<_Indexes...>,
- _IdxHolder, _Elements...>
+ template<std::size_t _Int, typename _Tp, std::size_t _Nm>
+ _Tp& get(array<_Tp, _Nm>&) noexcept;
+
+ template<std::size_t _Int, typename _Tp, std::size_t _Nm>
+ _Tp&& get(array<_Tp, _Nm>&&) noexcept;
+
+ template<std::size_t _Int, typename _Tp, std::size_t _Nm>
+ const _Tp& get(const array<_Tp, _Nm>&) noexcept;
+
+ template<typename>
+ struct __is_tuple_like_impl : false_type
+ { };
+
+ template<typename... _Tps>
+ struct __is_tuple_like_impl<tuple<_Tps...>> : true_type
+ { };
+
+ template<typename _T1, typename _T2>
+ struct __is_tuple_like_impl<pair<_T1, _T2>> : true_type
+ { };
+
+ template<typename _Tp, std::size_t _Nm>
+ struct __is_tuple_like_impl<array<_Tp, _Nm>> : true_type
+ { };
+
+ // Internal type trait that allows us to sfinae-protect tuple_cat.
+ template<typename _Tp>
+ struct __is_tuple_like
+ : public __is_tuple_like_impl<typename std::remove_cv
+ <typename std::remove_reference<_Tp>::type>::type>::type
+ { };
+
+ // Stores a tuple of indices. Also used by bind() to extract the elements
+ // in a tuple.
+ template<std::size_t... _Indexes>
+ struct _Index_tuple
{
- typedef typename __index_holder_impl<__i + 1,
- __index_holder<_Indexes..., __i>,
- _Elements...>::type type;
+ typedef _Index_tuple<_Indexes..., sizeof...(_Indexes)> __next;
};
-
- template<std::size_t __i, std::size_t... _Indexes>
- struct __index_holder_impl<__i, __index_holder<_Indexes...> >
- { typedef __index_holder<_Indexes...> type; };
- template<typename... _Elements>
- struct __make_index_holder
- : __index_holder_impl<0, __index_holder<>, _Elements...> { };
-
- template<typename... _TElements, std::size_t... _TIdx,
- typename... _UElements, std::size_t... _UIdx>
- inline constexpr tuple<_TElements..., _UElements...>
- __tuple_cat_helper(const tuple<_TElements...>& __t,
- const __index_holder<_TIdx...>&,
- const tuple<_UElements...>& __u,
- const __index_holder<_UIdx...>&)
- { return tuple<_TElements..., _UElements...>(get<_TIdx>(__t)...,
- get<_UIdx>(__u)...); }
-
- template<typename... _TElements, std::size_t... _TIdx,
- typename... _UElements, std::size_t... _UIdx>
- inline tuple<_TElements..., _UElements...>
- __tuple_cat_helper(tuple<_TElements...>&& __t,
- const __index_holder<_TIdx...>&,
- const tuple<_UElements...>& __u,
- const __index_holder<_UIdx...>&)
- { return tuple<_TElements..., _UElements...>
- (std::forward<_TElements>(get<_TIdx>(__t))..., get<_UIdx>(__u)...); }
-
- template<typename... _TElements, std::size_t... _TIdx,
- typename... _UElements, std::size_t... _UIdx>
- inline tuple<_TElements..., _UElements...>
- __tuple_cat_helper(const tuple<_TElements...>& __t,
- const __index_holder<_TIdx...>&,
- tuple<_UElements...>&& __u,
- const __index_holder<_UIdx...>&)
- { return tuple<_TElements..., _UElements...>
- (get<_TIdx>(__t)..., std::forward<_UElements>(get<_UIdx>(__u))...); }
-
- template<typename... _TElements, std::size_t... _TIdx,
- typename... _UElements, std::size_t... _UIdx>
- inline tuple<_TElements..., _UElements...>
- __tuple_cat_helper(tuple<_TElements...>&& __t,
- const __index_holder<_TIdx...>&,
- tuple<_UElements...>&& __u,
- const __index_holder<_UIdx...>&)
- { return tuple<_TElements..., _UElements...>
- (std::forward<_TElements>(get<_TIdx>(__t))...,
- std::forward<_UElements>(get<_UIdx>(__u))...); }
+ // Builds an _Index_tuple<0, 1, 2, ..., _Num-1>.
+ template<std::size_t _Num>
+ struct _Build_index_tuple
+ {
+ typedef typename _Build_index_tuple<_Num - 1>::__type::__next __type;
+ };
- template<typename... _TElements, typename... _UElements>
- inline constexpr tuple<_TElements..., _UElements...>
- tuple_cat(const tuple<_TElements...>& __t, const tuple<_UElements...>& __u)
+ template<>
+ struct _Build_index_tuple<0>
{
- return __tuple_cat_helper(__t, typename
- __make_index_holder<_TElements...>::type(),
- __u, typename
- __make_index_holder<_UElements...>::type());
- }
+ typedef _Index_tuple<> __type;
+ };
- template<typename... _TElements, typename... _UElements>
- inline tuple<_TElements..., _UElements...>
- tuple_cat(tuple<_TElements...>&& __t, const tuple<_UElements...>& __u)
+ template<std::size_t, typename, typename, std::size_t>
+ struct __make_tuple_impl;
+
+ template<std::size_t _Idx, typename _Tuple, typename... _Tp,
+ std::size_t _Nm>
+ struct __make_tuple_impl<_Idx, tuple<_Tp...>, _Tuple, _Nm>
{
- return __tuple_cat_helper(std::move(__t), typename
- __make_index_holder<_TElements...>::type(),
- __u, typename
- __make_index_holder<_UElements...>::type());
- }
+ typedef typename __make_tuple_impl<_Idx + 1, tuple<_Tp...,
+ typename std::tuple_element<_Idx, _Tuple>::type>, _Tuple, _Nm>::__type
+ __type;
+ };
- template<typename... _TElements, typename... _UElements>
- inline tuple<_TElements..., _UElements...>
- tuple_cat(const tuple<_TElements...>& __t, tuple<_UElements...>&& __u)
+ template<std::size_t _Nm, typename _Tuple, typename... _Tp>
+ struct __make_tuple_impl<_Nm, tuple<_Tp...>, _Tuple, _Nm>
{
- return __tuple_cat_helper(__t, typename
- __make_index_holder<_TElements...>::type(),
- std::move(__u), typename
- __make_index_holder<_UElements...>::type());
- }
+ typedef tuple<_Tp...> __type;
+ };
- template<typename... _TElements, typename... _UElements>
- inline tuple<_TElements..., _UElements...>
- tuple_cat(tuple<_TElements...>&& __t, tuple<_UElements...>&& __u)
+ template<typename _Tuple>
+ struct __do_make_tuple
+ : public __make_tuple_impl<0, tuple<>, _Tuple,
+ std::tuple_size<_Tuple>::value>
+ { };
+
+ // Returns the std::tuple equivalent of a tuple-like type.
+ template<typename _Tuple>
+ struct __make_tuple
+ : public __do_make_tuple<typename std::remove_cv
+ <typename std::remove_reference<_Tuple>::type>::type>
+ { };
+
+ // Combines several std::tuple's into a single one.
+ template<typename...>
+ struct __combine_tuples;
+
+ template<>
+ struct __combine_tuples<>
+ {
+ typedef tuple<> __type;
+ };
+
+ template<typename... _Ts>
+ struct __combine_tuples<tuple<_Ts...>>
{
- return __tuple_cat_helper(std::move(__t), typename
- __make_index_holder<_TElements...>::type(),
- std::move(__u), typename
- __make_index_holder<_UElements...>::type());
+ typedef tuple<_Ts...> __type;
+ };
+
+ template<typename... _T1s, typename... _T2s, typename... _Rem>
+ struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>, _Rem...>
+ {
+ typedef typename __combine_tuples<tuple<_T1s..., _T2s...>,
+ _Rem...>::__type __type;
+ };
+
+ // Computes the result type of tuple_cat given a set of tuple-like types.
+ template<typename... _Tpls>
+ struct __tuple_cat_result
+ {
+ typedef typename __combine_tuples
+ <typename __make_tuple<_Tpls>::__type...>::__type __type;
+ };
+
+ // Helper to determine the index set for the first tuple-like
+ // type of a given set.
+ template<typename...>
+ struct __make_1st_indices;
+
+ template<>
+ struct __make_1st_indices<>
+ {
+ typedef std::_Index_tuple<> __type;
+ };
+
+ template<typename _Tp, typename... _Tpls>
+ struct __make_1st_indices<_Tp, _Tpls...>
+ {
+ typedef typename std::_Build_index_tuple<std::tuple_size<
+ typename std::remove_reference<_Tp>::type>::value>::__type __type;
+ };
+
+ // Performs the actual concatenation by step-wise expanding tuple-like
+ // objects into the elements, which are finally forwarded into the
+ // result tuple.
+ template<typename _Ret, typename _Indices, typename... _Tpls>
+ struct __tuple_concater;
+
+ template<typename _Ret, std::size_t... _Is, typename _Tp, typename... _Tpls>
+ struct __tuple_concater<_Ret, std::_Index_tuple<_Is...>, _Tp, _Tpls...>
+ {
+ template<typename... _Us>
+ static _Ret
+ _S_do(_Tp&& __tp, _Tpls&&... __tps, _Us&&... __us)
+ {
+ typedef typename __make_1st_indices<_Tpls...>::__type __idx;
+ typedef __tuple_concater<_Ret, __idx, _Tpls...> __next;
+ return __next::_S_do(std::forward<_Tpls>(__tps)...,
+ std::forward<_Us>(__us)...,
+ std::get<_Is>(std::forward<_Tp>(__tp))...);
+ }
+ };
+
+ template<typename _Ret>
+ struct __tuple_concater<_Ret, std::_Index_tuple<>>
+ {
+ template<typename... _Us>
+ static _Ret
+ _S_do(_Us&&... __us)
+ {
+ return _Ret(std::forward<_Us>(__us)...);
+ }
+ };
+
+ template<typename... _Tpls>
+ inline typename
+ std::enable_if<__and_<__is_tuple_like<_Tpls>...>::value,
+ typename __tuple_cat_result<_Tpls...>::__type>::type
+ tuple_cat(_Tpls&&... __tpls)
+ {
+ typedef typename __tuple_cat_result<_Tpls...>::__type __ret;
+ typedef typename __make_1st_indices<_Tpls...>::__type __idx;
+ typedef __tuple_concater<__ret, __idx, _Tpls...> __concater;
+ return __concater::_S_do(std::forward<_Tpls>(__tpls)...);
}
template<typename... _Elements>
@@ -1007,29 +1083,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Types, typename _Alloc>
struct uses_allocator<tuple<_Types...>, _Alloc> : true_type { };
- /**
- * Stores a tuple of indices. Used by bind() to extract the elements
- * in a tuple.
- */
- template<std::size_t... _Indexes>
- struct _Index_tuple
- {
- typedef _Index_tuple<_Indexes..., sizeof...(_Indexes)> __next;
- };
-
- /// Builds an _Index_tuple<0, 1, 2, ..., _Num-1>.
- template<std::size_t _Num>
- struct _Build_index_tuple
- {
- typedef typename _Build_index_tuple<_Num-1>::__type::__next __type;
- };
-
- template<>
- struct _Build_index_tuple<0>
- {
- typedef _Index_tuple<> __type;
- };
-
// See stl_pair.h...
template<class _T1, class _T2>
template<typename _Tp, typename... _Args>
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9e40702..155f7df 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -45,23 +45,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @addtogroup metaprogramming
* @{
*/
- struct __sfinae_types
- {
- typedef char __one;
- typedef struct { char __arr[2]; } __two;
- };
+
+ /// integral_constant
+ template<typename _Tp, _Tp __v>
+ struct integral_constant
+ {
+ static constexpr _Tp value = __v;
+ typedef _Tp value_type;
+ typedef integral_constant<_Tp, __v> type;
+ constexpr operator value_type() { return value; }
+ };
+
+ /// typedef for true_type
+ typedef integral_constant<bool, true> true_type;
+
+ /// typedef for false_type
+ typedef integral_constant<bool, false> false_type;
+
+ template<typename _Tp, _Tp __v>
+ constexpr _Tp integral_constant<_Tp, __v>::value;
// Meta programming helper types.
template<bool, typename, typename>
struct conditional;
- template<typename _Tp, _Tp>
- struct integral_constant;
-
template<typename...>
struct __or_;
+ template<>
+ struct __or_<>
+ : public false_type
+ { };
+
template<typename _B1>
struct __or_<_B1>
: public _B1
@@ -80,6 +96,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename...>
struct __and_;
+ template<>
+ struct __and_<>
+ : public true_type
+ { };
+
template<typename _B1>
struct __and_<_B1>
: public _B1
@@ -100,26 +121,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public integral_constant<bool, !_Pp::value>
{ };
- // helper class.
-
- /// integral_constant
- template<typename _Tp, _Tp __v>
- struct integral_constant
- {
- static constexpr _Tp value = __v;
- typedef _Tp value_type;
- typedef integral_constant<_Tp, __v> type;
- constexpr operator value_type() { return value; }
- };
-
- /// typedef for true_type
- typedef integral_constant<bool, true> true_type;
-
- /// typedef for false_type
- typedef integral_constant<bool, false> false_type;
-
- template<typename _Tp, _Tp __v>
- constexpr _Tp integral_constant<_Tp, __v>::value;
+ struct __sfinae_types
+ {
+ typedef char __one;
+ typedef struct { char __arr[2]; } __two;
+ };
// primary type categories.
diff --git a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
index a5f4b28..195b9c2 100644
--- a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
@@ -19,7 +19,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-error "static assertion failed" "" { target *-*-* } 1725 }
+// { dg-error "static assertion failed" "" { target *-*-* } 1731 }
#include <utility>
diff --git a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
index f37d4fb..b3266580 100644
--- a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
@@ -48,5 +48,5 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 40 }
// { dg-error "required from here" "" { target *-*-* } 42 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1511 }
-// { dg-error "declaration of" "" { target *-*-* } 1475 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1517 }
+// { dg-error "declaration of" "" { target *-*-* } 1481 }
diff --git a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
index 497f170..3de08b3 100644
--- a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
@@ -48,5 +48,5 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 40 }
// { dg-error "required from here" "" { target *-*-* } 42 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1435 }
-// { dg-error "declaration of" "" { target *-*-* } 1399 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1441 }
+// { dg-error "declaration of" "" { target *-*-* } 1405 }
diff --git a/libstdc++-v3/testsuite/20_util/tuple/creation_functions/constexpr.cc b/libstdc++-v3/testsuite/20_util/tuple/creation_functions/constexpr.cc
index a5b5441..82bbe1f 100644
--- a/libstdc++-v3/testsuite/20_util/tuple/creation_functions/constexpr.cc
+++ b/libstdc++-v3/testsuite/20_util/tuple/creation_functions/constexpr.cc
@@ -63,6 +63,7 @@ test_get()
}
// tuple_cat
+#if 0
void
test_tuple_cat()
{
@@ -73,7 +74,7 @@ test_tuple_cat()
constexpr tuple_type2 t2 { 55, 99, 77.77 };
constexpr auto cat1 = std::tuple_cat(t1, t2);
}
-
+#endif
int
main()
@@ -84,7 +85,9 @@ main()
test_get();
+#if 0
test_tuple_cat();
+#endif
return 0;
}
diff --git a/libstdc++-v3/testsuite/20_util/tuple/creation_functions/tuple_cat.cc b/libstdc++-v3/testsuite/20_util/tuple/creation_functions/tuple_cat.cc
new file mode 100644
index 0000000..b2279a1
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/creation_functions/tuple_cat.cc
@@ -0,0 +1,131 @@
+// { dg-options "-std=gnu++0x" }
+
+// Copyright (C) 2011 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// Tuple
+
+#include <tuple>
+#include <array>
+
+static_assert(std::is_same<decltype(std::tuple_cat()),
+ std::tuple<>>::value, "Error");
+static_assert(std::is_same<decltype(std::tuple_cat
+ (std::declval<std::tuple<>>())),
+ std::tuple<>>::value, "Error");
+static_assert(std::is_same<decltype(std::tuple_cat
+ (std::declval<std::tuple<>&>())),
+ std::tuple<>>::value, "Error");
+static_assert(std::is_same<decltype(std::tuple_cat
+ (std::declval<const std::tuple<>>())),
+ std::tuple<>>::value, "Error");
+static_assert(std::is_same<decltype(std::tuple_cat
+ (std::declval<const std::tuple<>&>())),
+ std::tuple<>>::value, "Error");
+static_assert(std::is_same<decltype(std::tuple_cat
+ (std::declval<std::pair<int, bool>>())),
+ std::tuple<int, bool>>::value, "Error");
+static_assert(std::is_same<decltype(std::tuple_cat
+ (std::declval<std::pair<int, bool>&>())),
+ std::tuple<int, bool>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat(std::declval<const std::pair<int, bool>>())),
+ std::tuple<int, bool>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat(std::declval<const std::pair<int, bool>&>())),
+ std::tuple<int, bool>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat(std::declval<std::array<int, 3>>())),
+ std::tuple<int, int, int>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat(std::declval<std::array<int, 3>&>())),
+ std::tuple<int, int, int>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat(std::declval<const std::array<int, 3>>())),
+ std::tuple<int, int, int>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat(std::declval<const std::array<int, 3>&>())),
+ std::tuple<int, int, int>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat
+ (std::declval<std::tuple<>>(), std::declval<std::tuple<>>())),
+ std::tuple<>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat
+ (std::declval<std::tuple<>>(), std::declval<std::tuple<>>(),
+ std::declval<std::tuple<>>())), std::tuple<>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat
+ (std::declval<std::tuple<>>(),
+ std::declval<std::array<char, 0>>(),
+ std::declval<std::array<int, 0>>(),
+ std::declval<std::tuple<>>())), std::tuple<>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat
+ (std::declval<std::tuple<int>>(),
+ std::declval<std::tuple<double>>())),
+ std::tuple<int, double>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat
+ (std::declval<std::tuple<int>>(),
+ std::declval<std::tuple<double>>(),
+ std::declval<std::tuple<const long&>>())),
+ std::tuple<int, double, const long&>>::value, "Error");
+static_assert(std::is_same<decltype
+ (std::tuple_cat
+ (std::declval<std::array<wchar_t, 3>&>(),
+ std::declval<std::tuple<double>>(),
+ std::declval<std::tuple<>>(),
+ std::declval<std::tuple<unsigned&>>(),
+ std::declval<std::pair<bool, std::nullptr_t>>())),
+ std::tuple<wchar_t, wchar_t, wchar_t,
+ double, unsigned&, bool, std::nullptr_t>
+ >::value, "Error");
+
+int main()
+{
+ std::tuple_cat();
+ std::tuple_cat(std::tuple<>{ });
+ std::tuple_cat(std::tuple<>{ }, std::tuple<>{ });
+ std::array<int, 3> a3;
+ std::tuple_cat(a3);
+ std::pair<double, bool> pdb;
+ std::tuple<unsigned, float, std::nullptr_t, void*> t;
+ int i{ };
+ double d{ };
+ int* pi{ };
+ std::tuple<int&, double&, int*&> to{i, d, pi};
+ std::tuple_cat(pdb);
+ std::tuple_cat(to);
+ std::tuple_cat(to, to);
+ std::tuple_cat(a3, pdb);
+ std::tuple_cat(a3, pdb, t);
+ std::tuple_cat(a3, pdb, t, a3);
+ std::tuple_cat(a3, pdb, t, a3, pdb, t);
+
+ static_assert(std::is_same<decltype
+ (std::tuple_cat(a3, pdb, t, a3, pdb, t)),
+ std::tuple<int, int, int, double, bool,
+ unsigned, float, std::nullptr_t, void*,
+ int, int, int, double, bool, unsigned,
+ float, std::nullptr_t, void*>
+ >::value, "Error");
+
+ std::tuple_cat(std::tuple<int, char, void*>{}, to, a3,
+ std::tuple<>{}, std::pair<float,
+ std::nullptr_t>{}, pdb, to);
+}