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
This commit is contained in:
Daniel Krugler 2011-09-11 22:10:21 +00:00 committed by Paolo Carlini
parent fa11ae6c72
commit ac65b7d221
9 changed files with 360 additions and 151 deletions

View File

@ -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...

View File

@ -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>

View File

@ -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))...); }
template<typename... _TElements, typename... _UElements>
inline constexpr tuple<_TElements..., _UElements...>
tuple_cat(const tuple<_TElements...>& __t, const tuple<_UElements...>& __u)
// Builds an _Index_tuple<0, 1, 2, ..., _Num-1>.
template<std::size_t _Num>
struct _Build_index_tuple
{
return __tuple_cat_helper(__t, typename
__make_index_holder<_TElements...>::type(),
__u, typename
__make_index_holder<_UElements...>::type());
}
typedef typename _Build_index_tuple<_Num - 1>::__type::__next __type;
};
template<typename... _TElements, typename... _UElements>
inline tuple<_TElements..., _UElements...>
tuple_cat(tuple<_TElements...>&& __t, const tuple<_UElements...>& __u)
template<>
struct _Build_index_tuple<0>
{
return __tuple_cat_helper(std::move(__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(const tuple<_TElements...>& __t, tuple<_UElements...>&& __u)
{
return __tuple_cat_helper(__t, typename
__make_index_holder<_TElements...>::type(),
std::move(__u), typename
__make_index_holder<_UElements...>::type());
}
template<std::size_t, typename, typename, std::size_t>
struct __make_tuple_impl;
template<typename... _TElements, typename... _UElements>
inline tuple<_TElements..., _UElements...>
tuple_cat(tuple<_TElements...>&& __t, tuple<_UElements...>&& __u)
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(),
std::move(__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<std::size_t _Nm, typename _Tuple, typename... _Tp>
struct __make_tuple_impl<_Nm, tuple<_Tp...>, _Tuple, _Nm>
{
typedef tuple<_Tp...> __type;
};
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...>>
{
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>

View File

@ -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.

View File

@ -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>

View File

@ -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 }

View File

@ -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 }

View File

@ -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;
}

View File

@ -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);
}