Commit d355635e by Jonathan Wakely Committed by Jonathan Wakely

Refactor SFINAE constraints on std::tuple constructors

Replace the _TC class template with the better-named _TupleConstraints
one, which provides a different set of member functions. The new members
do not distinguish construction from lvalues and rvalues, but expects
the caller to do that by providing different template arguments. Within
the std::tuple primary template and std::tuple<T1, T2> partial
specialization the _TupleConstraints members are used via new alias
templates like _ImplicitCtor and _ExplicitCtor which makes the
constructor constraints less verbose and repetitive. For example, where
we previously had:

     template<typename... _UElements, typename
             enable_if<
                _TMC<_UElements...>::template
                   _MoveConstructibleTuple<_UElements...>()
                 && _TMC<_UElements...>::template
                   _ImplicitlyMoveConvertibleTuple<_UElements...>()
                 && (sizeof...(_Elements) >= 1),
       bool>::type=true>
       constexpr tuple(_UElements&&... __elements)

We now have:

     template<typename... _UElements,
             bool _Valid = __valid_args<_UElements...>(),
             _ImplicitCtor<_Valid, _UElements...> = true>
      constexpr
      tuple(_UElements&&... __elements)

There are two semantic changes as a result of the refactoring:

- The allocator-extended default constructor is now constrained.
- The rewritten constraints fix PR 90700.

	* include/std/tuple (_TC): Replace with _TupleConstraints.
	(_TupleConstraints): New helper for SFINAE constraints, with more
	expressive member functions to reduce duplication when used.
	(tuple::_TC2, tuple::_TMC, tuple::_TNTC): Remove.
	(tuple::_TCC): Replace dummy type parameter with bool non-type
	parameter that can be used to check the pack size.
	(tuple::_ImplicitDefaultCtor, tuple::_ExplicitDefaultCtor)
	(tuple::_ImplicitCtor, tuple::_ExplicitCtor): New alias templates for
	checking constraints in constructors.
	(tuple::__valid_args, tuple::_UseOtherCtor, tuple::__use_other_ctor):
	New SFINAE helpers.
	(tuple::tuple): Use new helpers to reduce repitition in constraints.
	(tuple::tuple(allocator_arg_t, const Alloc&)): Constrain.
	(tuple<T1, T2>::_TCC, tuple<T1, T2>::_ImplicitDefaultCtor)
	(tuple<T1, T2>::_ExplicitDefaultCtor, tuple<T1, T2>::_ImplicitCtor)
	(tuple<T1, T2>::_ExplicitCtor): New alias templates for checking
	constraints in constructors.
	(tuple::__is_alloc_arg()): New SFINAE helpers.
	(tuple<T1, T2>::tuple): Use new helpers to reduce repitition in
	constraints.
	(tuple<T1, T2>::tuple(allocator_arg_t, const Alloc&)): Constrain.
	* testsuite/20_util/tuple/cons/90700.cc: New test.
	* testsuite/20_util/tuple/cons/allocators.cc: Add default constructor
	to meet new constraint on allocator-extended default constructor.

From-SVN: r271998
parent ec573765
2019-06-06 Jonathan Wakely <jwakely@redhat.com>
* include/std/tuple (_TC): Replace with _TupleConstraints.
(_TupleConstraints): New helper for SFINAE constraints, with more
expressive member functions to reduce duplication when used.
(tuple::_TC2, tuple::_TMC, tuple::_TNTC): Remove.
(tuple::_TCC): Replace dummy type parameter with bool non-type
parameter that can be used to check the pack size.
(tuple::_ImplicitDefaultCtor, tuple::_ExplicitDefaultCtor)
(tuple::_ImplicitCtor, tuple::_ExplicitCtor): New alias templates for
checking constraints in constructors.
(tuple::__valid_args, tuple::_UseOtherCtor, tuple::__use_other_ctor):
New SFINAE helpers.
(tuple::tuple): Use new helpers to reduce repitition in constraints.
(tuple::tuple(allocator_arg_t, const Alloc&)): Constrain.
(tuple<T1, T2>::_TCC, tuple<T1, T2>::_ImplicitDefaultCtor)
(tuple<T1, T2>::_ExplicitDefaultCtor, tuple<T1, T2>::_ImplicitCtor)
(tuple<T1, T2>::_ExplicitCtor): New alias templates for checking
constraints in constructors.
(tuple::__is_alloc_arg()): New SFINAE helpers.
(tuple<T1, T2>::tuple): Use new helpers to reduce repitition in
constraints.
(tuple<T1, T2>::tuple(allocator_arg_t, const Alloc&)): Constrain.
* testsuite/20_util/tuple/cons/90700.cc: New test.
* testsuite/20_util/tuple/cons/allocators.cc: Add default constructor
to meet new constraint on allocator-extended default constructor.
2019-06-03 Jonathan Wakely <jwakely@redhat.com> 2019-06-03 Jonathan Wakely <jwakely@redhat.com>
* include/bits/stl_map.h (map): Disable static assert for C++98 mode. * include/bits/stl_map.h (map): Disable static assert for C++98 mode.
......
// Copyright (C) 2019 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/>.
// { dg-do compile { target c++11 } }
#include <tuple>
#include <memory>
struct X { };
struct Y
{
Y(const std::tuple<X>&) = delete;
Y(std::tuple<X>&&) { throw 1; }
Y(const X&) { }
};
struct Z
{
Z(X&&) { }
Z(const std::tuple<X>&) { throw 1; }
Z(std::tuple<X>&&) = delete;
};
void
test01()
{
// PR libstdc++/90700 wrong constraints on constructor
const std::allocator<int> a;
const std::tuple<X> x;
static_assert(!std::is_convertible<const std::tuple<X>&, Y>::value, "");
static_assert(!std::is_constructible<Y, const std::tuple<X>&>::value, "");
static_assert(!std::is_same<Y, X>::value, "");
// should use tuple<Y>::tuple<X>(allocator_arg_t, const A&, const tuple<X>&)
// and construct Y from X:
std::tuple<Y> y(std::allocator_arg, a, x);
}
void
test02()
{
const std::allocator<int> a;
std::tuple<X> x;
static_assert(!std::is_convertible<std::tuple<X>, Z>::value, "");
static_assert(!std::is_constructible<Z, std::tuple<X>>::value, "");
static_assert(!std::is_same<Z, X>::value, "");
// should use tuple<Z>::tuple<X>(allocator_arg_t, const A&, tuple<X>&&)
// and construct Z from X:
std::tuple<Z> z(std::allocator_arg, a, std::move(x));
}
...@@ -186,12 +186,26 @@ void test03() ...@@ -186,12 +186,26 @@ void test03()
struct dr2586 struct dr2586
{ {
using allocator_type = std::allocator<int>; using allocator_type = std::allocator<int>;
dr2586() { }
dr2586(std::allocator_arg_t, allocator_type&&) { } dr2586(std::allocator_arg_t, allocator_type&&) { }
dr2586(const allocator_type&) { } dr2586(const allocator_type&) : expected(true) { }
bool expected = false;
}; };
const dr2586::allocator_type a; const dr2586::allocator_type a;
std::tuple<dr2586> t{std::allocator_arg, a}; std::tuple<dr2586> t{std::allocator_arg, a};
VERIFY( std::get<0>(t).expected );
}
void test04()
{
struct X {
X(std::allocator_arg_t) { }
};
// The element types are not default constructible, so the allocator-extended
// default constructor should not participate in overload resolution.
std::tuple<X, void(&)()> t(std::allocator_arg, *+[]{});
} }
int main() int main()
...@@ -199,5 +213,6 @@ int main() ...@@ -199,5 +213,6 @@ int main()
test01(); test01();
test02(); test02();
test03(); test03();
test04();
return 0; return 0;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment