On 13/06/15 21:05 +0300, Ville Voutilainen wrote:
Another round! The new patch - makes sure not to change non-deduced parameters to deduced ones, and adds tests for that. - removes the name of the bool non-type template parameter for the 'concepts'. - introduces shortcuts for making the use of the 'concepts' more readable.
These bits are lovely jubbly.
- changes library tag types into non-default-constructible ones. Without this, we can run into an ambiguity between the constructor template that takes (const _T1&, const _T2&) and the one that takes (allocator_arg_t, Alloc), when the call site calls it with ({}, somethingelse). We could avoid that by just not doing that in the library (experimental string searchers do that), but it's just daft to allow default-constructing a library tag type. I have filed an LWG issue to fix all tag types, but this patch doesn't yet touch nothrow_t and optional's in_place_t. I expect to submit follow-up patches for that.
I agree that default-constructing tag types doesn't make sense when we have named constants to use. I also think it's a real pain in the posterior that tuple<T,U>( {}, T{} } is ambiguous, but I'm not comfortable with making all those tag types non-default constructible until we get an indication how LWG feel about the proposal. So I've removed that part of the patch and "fixed" the searcher that used {} and became ambiguous. I have a follow-up patch coming that will prevent the ambiguities differently. Tested ppc64le-linux and committed to trunk.
commit b80baac2fa84492f90e9c4137190330cf7c53fee Author: Jonathan Wakely <jwak...@redhat.com> Date: Mon Jun 29 15:07:36 2015 +0100 2015-06-30 Ville Voutilainen <ville.voutilai...@gmail.com> Implement N4387, "Improving pair and tuple", and LWG 2367. * include/bits/stl_pair.h (_ConstructiblePair, _ImplicitlyConvertiblePair, _MoveConstructiblePair, _ImplicitlyMoveConvertiblePair): New. (pair()): Constrain it. (pair(const _T1&, const _T2&), pair(const pair<_U1, _U2>&), pair(_U1&&, const _T2&), pair(const _T1&, _U2&&), pair(_U1&&, _U2&&), pair(pair<_U1, _U2>&&)): Make conditionally explicit. * include/std/tuple (_TC, tuple::_TC2, tuple::TCC, tuple::TMC): New. (tuple()): Constrain it. (tuple(const _UElements&...), tuple(_UElements&&...), tuple(const tuple<_UElements...>&), tuple(tuple<_UElements...>&&), tuple(allocator_arg_t, const _Alloc&, const _UElements&...), tuple(allocator_arg_t, const _Alloc&, _UElements&&...), tuple(allocator_arg_t, const _Alloc&, const tuple<_UElements...>&), tuple(allocator_arg_t, const _Alloc&, tuple<_UElements...>&&), tuple(const pair<_U1, _U2>&), tuple(pair<_U1, _U2>&&), tuple(allocator_arg_t, const _Alloc&, const pair<_U1, _U2>&), tuple(allocator_arg_t, const _Alloc&, pair<_U1, _U2>&&)): Make conditionally explicit. * include/experimental/functional (__boyer_moore_array_base): Name array type explicitly instead of using an empty braced-init-list. * testsuite/20_util/pair/cons/explicit_construct.cc: New. * testsuite/20_util/pair/piecewise.cc: Use piecewise_construct. * testsuite/20_util/pair/requirements/dr2367.cc: New. * testsuite/20_util/tuple/cons/explicit_construct.cc: New. * testsuite/20_util/tuple/requirements/dr2367.cc: New. diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 490b005..6672ecb 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -84,6 +84,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<std::size_t...> struct _Index_tuple; + + // Concept utility functions, reused in conditionally-explicit + // constructors. + template <typename _T1, typename _T2, typename _U1, typename _U2> + constexpr bool _ConstructiblePair() + { + return __and_<is_constructible<_T1, const _U1&>, + is_constructible<_T2, const _U2&>>::value; + } + + template <typename _T1, typename _T2, typename _U1, typename _U2> + constexpr bool _ImplicitlyConvertiblePair() + { + return __and_<is_convertible<const _U1&, _T1>, + is_convertible<const _U2&, _T2>>::value; + } + + template <typename _T1, typename _T2, typename _U1, typename _U2> + constexpr bool _MoveConstructiblePair() + { + return __and_<is_constructible<_T1, _U1&&>, + is_constructible<_T2, _U2&&>>::value; + } + + template <typename _T1, typename _T2, typename _U1, typename _U2> + constexpr bool _ImplicitlyMoveConvertiblePair() + { + return __and_<is_convertible<_U1&&, _T1>, + is_convertible<_U2&&, _T2>>::value; + } + + #endif /** @@ -105,52 +137,136 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 265. std::pair::pair() effects overly restrictive /** The default constructor creates @c first and @c second using their * respective default constructors. */ +#if __cplusplus >= 201103L + template <typename _U1 = _T1, + typename _U2 = _T2, + typename enable_if<__and_< + is_default_constructible<_U1>, + is_default_constructible<_U2>> + ::value, bool>::type = true> +#endif _GLIBCXX_CONSTEXPR pair() : first(), second() { } /** Two objects may be passed to a @c pair constructor to be copied. */ - _GLIBCXX_CONSTEXPR pair(const _T1& __a, const _T2& __b) +#if __cplusplus < 201103L + pair(const _T1& __a, const _T2& __b) + : first(__a), second(__b) { } +#else + template<typename _U1 = _T1, typename _U2=_T2, typename + enable_if<_ConstructiblePair<_T1, _T2, _U1, _U2>() + && _ImplicitlyConvertiblePair<_T1, _T2, _U1, _U2>(), + bool>::type=true> + constexpr pair(const _T1& __a, const _T2& __b) : first(__a), second(__b) { } + template<typename _U1 = _T1, typename _U2=_T2, typename + enable_if<_ConstructiblePair<_T1, _T2, _U1, _U2>() + && !_ImplicitlyConvertiblePair<_T1, _T2, _U1, _U2>(), + bool>::type=false> + explicit constexpr pair(const _T1& __a, const _T2& __b) + : first(__a), second(__b) { } +#endif + /** There is also a templated copy ctor for the @c pair class itself. */ #if __cplusplus < 201103L template<class _U1, class _U2> pair(const pair<_U1, _U2>& __p) : first(__p.first), second(__p.second) { } #else - template<class _U1, class _U2, class = typename - enable_if<__and_<is_convertible<const _U1&, _T1>, - is_convertible<const _U2&, _T2>>::value>::type> - constexpr pair(const pair<_U1, _U2>& __p) + template<class _U1, class _U2, typename + enable_if<_ConstructiblePair<_T1, _T2, _U1, _U2>() + && _ImplicitlyConvertiblePair<_T1, _T2, _U1, _U2>(), + bool>::type=true> + constexpr pair(const pair<_U1, _U2>& __p) + : first(__p.first), second(__p.second) { } + + template<class _U1, class _U2, typename + enable_if<_ConstructiblePair<_T1, _T2, _U1, _U2>() + && !_ImplicitlyConvertiblePair<_T1, _T2, _U1, _U2>(), + bool>::type=false> + explicit constexpr pair(const pair<_U1, _U2>& __p) : first(__p.first), second(__p.second) { } constexpr pair(const pair&) = default; constexpr pair(pair&&) = default; // DR 811. - template<class _U1, class = typename - enable_if<is_convertible<_U1, _T1>::value>::type> - constexpr pair(_U1&& __x, const _T2& __y) - : first(std::forward<_U1>(__x)), second(__y) { } - - template<class _U2, class = typename - enable_if<is_convertible<_U2, _T2>::value>::type> - constexpr pair(const _T1& __x, _U2&& __y) - : first(__x), second(std::forward<_U2>(__y)) { } - - template<class _U1, class _U2, class = typename - enable_if<__and_<is_convertible<_U1, _T1>, - is_convertible<_U2, _T2>>::value>::type> + template<class _U1, typename + enable_if<_ConstructiblePair<_T2, _T2, _T2, _T2>() + && _MoveConstructiblePair<_T1, _T2, _U1, _T2>() + && _ImplicitlyConvertiblePair<_T2, _T2, _T2, _T2>() + && _ImplicitlyMoveConvertiblePair<_T1, _T2, + _U1, _T2>(), + bool>::type=true> + constexpr pair(_U1&& __x, const _T2& __y) + : first(std::forward<_U1>(__x)), second(__y) { } + + template<class _U1, typename + enable_if<_ConstructiblePair<_T2, _T2, _T2, _T2>() + && _MoveConstructiblePair<_T1, _T2, _U1, _T2>() + && (!_ImplicitlyConvertiblePair<_T2, _T2, _T2, _T2>() + || !_ImplicitlyMoveConvertiblePair<_T1, _T2, + _U1, _T2>()), + bool>::type=false> + explicit constexpr pair(_U1&& __x, const _T2& __y) + : first(std::forward<_U1>(__x)), second(__y) { } + + template<class _U2, typename + enable_if<_ConstructiblePair<_T1, _T1, _T1, _T1>() + && _MoveConstructiblePair<_T1, _T2, _T1, _U2>() + && _ImplicitlyConvertiblePair<_T1, _T1, _T1, _T1>() + && _ImplicitlyMoveConvertiblePair<_T1, _T2, + _T1, _U2>(), + bool>::type=true> + constexpr pair(const _T1& __x, _U2&& __y) + : first(__x), second(std::forward<_U2>(__y)) { } + + template<class _U2, typename + enable_if<_ConstructiblePair<_T1, _T1, _T1, _T1>() + && _MoveConstructiblePair<_T1, _T2, _T1, _U2>() + && (!_ImplicitlyConvertiblePair<_T1, _T1, _T1, _T1>() + || !_ImplicitlyMoveConvertiblePair<_T1, _T2, + _T1, _U2>()), + bool>::type=false> + explicit pair(const _T1& __x, _U2&& __y) + : first(__x), second(std::forward<_U2>(__y)) { } + + template<class _U1, class _U2, typename + enable_if<_MoveConstructiblePair<_T1, _T2, _U1, _U2>() + && _ImplicitlyMoveConvertiblePair<_T1, _T2, + _U1, _U2>(), + bool>::type=true> constexpr pair(_U1&& __x, _U2&& __y) : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { } - template<class _U1, class _U2, class = typename - enable_if<__and_<is_convertible<_U1, _T1>, - is_convertible<_U2, _T2>>::value>::type> + template<class _U1, class _U2, typename + enable_if<_MoveConstructiblePair<_T1, _T2, _U1, _U2>() + && !_ImplicitlyMoveConvertiblePair<_T1, _T2, + _U1, _U2>(), + bool>::type=false> + explicit constexpr pair(_U1&& __x, _U2&& __y) + : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { } + + + template<class _U1, class _U2, typename + enable_if<_MoveConstructiblePair<_T1, _T2, _U1, _U2>() + && _ImplicitlyMoveConvertiblePair<_T1, _T2, + _U1, _U2>(), + bool>::type=true> constexpr pair(pair<_U1, _U2>&& __p) : first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) { } + template<class _U1, class _U2, typename + enable_if<_MoveConstructiblePair<_T1, _T2, _U1, _U2>() + && !_ImplicitlyMoveConvertiblePair<_T1, _T2, + _U1, _U2>(), + bool>::type=false> + explicit constexpr pair(pair<_U1, _U2>&& __p) + : first(std::forward<_U1>(__p.first)), + second(std::forward<_U2>(__p.second)) { } + template<typename... _Args1, typename... _Args2> pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>); diff --git a/libstdc++-v3/include/experimental/functional b/libstdc++-v3/include/experimental/functional index 0472f59..c6b9800 100644 --- a/libstdc++-v3/include/experimental/functional +++ b/libstdc++-v3/include/experimental/functional @@ -124,7 +124,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _RAIter, typename _Unused> __boyer_moore_array_base(_RAIter __pat, size_t __patlen, _Unused&&, _Pred&& __pred) - : _M_bad_char{ {}, std::move(__pred) } + : _M_bad_char{ std::array<_Tp, _Len>{}, std::move(__pred) } { std::get<0>(_M_bad_char).fill(__patlen); if (__patlen > 0) diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 0504012..59b992a 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -457,63 +457,236 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + + // Concept utility functions, reused in conditionally-explicit + // constructors. + template<bool, typename... _Elements> + struct _TC + { + template<typename... _UElements> + static constexpr bool _ConstructibleTuple() + { + return __and_<is_constructible<_Elements, const _UElements&>...>::value; + } + + template<typename... _UElements> + static constexpr bool _ImplicitlyConvertibleTuple() + { + return __and_<is_convertible<const _UElements&, _Elements>...>::value; + } + + template<typename... _UElements> + static constexpr bool _MoveConstructibleTuple() + { + return __and_<is_constructible<_Elements, _UElements&&>...>::value; + } + + template<typename... _UElements> + static constexpr bool _ImplicitlyMoveConvertibleTuple() + { + return __and_<is_convertible<_UElements&&, _Elements>...>::value; + } + }; + + template<typename... _Elements> + struct _TC<false, _Elements...> + { + template<typename... _UElements> + static constexpr bool _ConstructibleTuple() + { + return false; + } + + template<typename... _UElements> + static constexpr bool _ImplicitlyConvertibleTuple() + { + return false; + } + + template<typename... _UElements> + static constexpr bool _MoveConstructibleTuple() + { + return false; + } + + template<typename... _UElements> + static constexpr bool _ImplicitlyMoveConvertibleTuple() + { + return false; + } + }; + /// Primary class template, tuple template<typename... _Elements> class tuple : public _Tuple_impl<0, _Elements...> { typedef _Tuple_impl<0, _Elements...> _Inherited; + // Used for constraining the default constructor so + // that it becomes dependent on the constraints. + template<typename _Dummy> + struct _TC2 + { + static constexpr bool _DefaultConstructibleTuple() + { + return __and_<is_default_constructible<_Elements>...>::value; + } + }; + public: + template<typename _Dummy = void, + typename enable_if<_TC2<_Dummy>:: + _DefaultConstructibleTuple(), + bool>::type = true> constexpr tuple() : _Inherited() { } - explicit - constexpr tuple(const _Elements&... __elements) + // Shortcut for the cases where constructors taking _Elements... + // need to be constrained. + template<typename _Dummy> using _TCC = + _TC<is_same<_Dummy, void>::value, + _Elements...>; + + template<typename _Dummy = void, + typename enable_if< + _TCC<_Dummy>::template + _ConstructibleTuple<_Elements...>() + && _TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_Elements...>() + && (sizeof...(_Elements) >= 1), + bool>::type=true> + constexpr tuple(const _Elements&... __elements) : _Inherited(__elements...) { } - template<typename... _UElements, typename = typename - enable_if<__and_<is_convertible<_UElements, - _Elements>...>::value>::type> - explicit + template<typename _Dummy = void, + typename enable_if< + _TCC<_Dummy>::template + _ConstructibleTuple<_Elements...>() + && !_TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_Elements...>() + && (sizeof...(_Elements) >= 1), + bool>::type=false> + explicit constexpr tuple(const _Elements&... __elements) + : _Inherited(__elements...) { } + + // Shortcut for the cases where constructors taking _UElements... + // need to be constrained. + template<typename... _UElements> using _TMC = + _TC<(sizeof...(_Elements) == sizeof...(_UElements)), + _Elements...>; + + 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) + : _Inherited(std::forward<_UElements>(__elements)...) { } + + template<typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _MoveConstructibleTuple<_UElements...>() + && !_TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>() + && (sizeof...(_Elements) >= 1), + bool>::type=false> + explicit constexpr tuple(_UElements&&... __elements) : _Inherited(std::forward<_UElements>(__elements)...) { } constexpr tuple(const tuple&) = default; constexpr tuple(tuple&&) = default; - template<typename... _UElements, typename = typename - enable_if<__and_<is_convertible<const _UElements&, - _Elements>...>::value>::type> + template<typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _ConstructibleTuple<_UElements...>() + && _TMC<_UElements...>::template + _ImplicitlyConvertibleTuple<_UElements...>(), + bool>::type=true> constexpr tuple(const tuple<_UElements...>& __in) : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) { } - template<typename... _UElements, typename = typename - enable_if<__and_<is_convertible<_UElements, - _Elements>...>::value>::type> + template<typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _ConstructibleTuple<_UElements...>() + && !_TMC<_UElements...>::template + _ImplicitlyConvertibleTuple<_UElements...>(), + bool>::type=false> + explicit constexpr tuple(const tuple<_UElements...>& __in) + : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) + { } + + template<typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _MoveConstructibleTuple<_UElements...>() + && _TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>(), + bool>::type=true> constexpr tuple(tuple<_UElements...>&& __in) : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } + template<typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _MoveConstructibleTuple<_UElements...>() + && !_TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>(), + bool>::type=false> + explicit constexpr tuple(tuple<_UElements...>&& __in) + : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } + // Allocator-extended constructors. template<typename _Alloc> tuple(allocator_arg_t __tag, const _Alloc& __a) : _Inherited(__tag, __a) { } - template<typename _Alloc> + template<typename _Alloc, typename _Dummy = void, + typename enable_if< + _TCC<_Dummy>::template + _ConstructibleTuple<_Elements...>() + && _TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_Elements...>(), + bool>::type=true> tuple(allocator_arg_t __tag, const _Alloc& __a, const _Elements&... __elements) : _Inherited(__tag, __a, __elements...) { } - template<typename _Alloc, typename... _UElements, typename = typename - enable_if<sizeof...(_UElements) - == sizeof...(_Elements)>::type> + template<typename _Alloc, typename _Dummy = void, + typename enable_if< + _TCC<_Dummy>::template + _ConstructibleTuple<_Elements...>() + && !_TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_Elements...>(), + bool>::type=false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const _Elements&... __elements) + : _Inherited(__tag, __a, __elements...) { } + + template<typename _Alloc, typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _MoveConstructibleTuple<_UElements...>() + && _TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>(), + bool>::type=true> tuple(allocator_arg_t __tag, const _Alloc& __a, _UElements&&... __elements) : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) { } + template<typename _Alloc, typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _MoveConstructibleTuple<_UElements...>() + && !_TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>(), + bool>::type=false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + _UElements&&... __elements) + : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) + { } + template<typename _Alloc> tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) : _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { } @@ -522,24 +695,54 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } - template<typename _Alloc, typename... _UElements, typename = typename - enable_if<sizeof...(_UElements) - == sizeof...(_Elements)>::type> + template<typename _Alloc, typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _ConstructibleTuple<_UElements...>() + && _TMC<_UElements...>::template + _ImplicitlyConvertibleTuple<_UElements...>(), + bool>::type=true> tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple<_UElements...>& __in) : _Inherited(__tag, __a, static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) { } - template<typename _Alloc, typename... _UElements, typename = typename - enable_if<sizeof...(_UElements) - == sizeof...(_Elements)>::type> + template<typename _Alloc, typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _ConstructibleTuple<_UElements...>() + && !_TMC<_UElements...>::template + _ImplicitlyConvertibleTuple<_UElements...>(), + bool>::type=false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const tuple<_UElements...>& __in) + : _Inherited(__tag, __a, + static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) + { } + + template<typename _Alloc, typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _MoveConstructibleTuple<_UElements...>() + && _TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>(), + bool>::type=true> tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_UElements...>&& __in) : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } + template<typename _Alloc, typename... _UElements, typename + enable_if<_TMC<_UElements...>::template + _MoveConstructibleTuple<_UElements...>() + && !_TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>(), + bool>::type=false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + tuple<_UElements...>&& __in) + : _Inherited(__tag, __a, + static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) + { } + tuple& operator=(const tuple& __in) { @@ -582,7 +785,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; // Explicit specialization, zero-element tuple. - template<> + template<> class tuple<> { public: @@ -597,65 +800,190 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef _Tuple_impl<0, _T1, _T2> _Inherited; public: + template <typename _U1 = _T1, + typename _U2 = _T2, + typename enable_if<__and_< + is_default_constructible<_U1>, + is_default_constructible<_U2>> + ::value, bool>::type = true> + constexpr tuple() : _Inherited() { } - explicit - constexpr tuple(const _T1& __a1, const _T2& __a2) - : _Inherited(__a1, __a2) { } - - template<typename _U1, typename _U2, typename = typename - enable_if<__and_<is_convertible<_U1, _T1>, - is_convertible<_U2, _T2>>::value>::type> - explicit + // Shortcut for the cases where constructors taking _T1, _T2 + // need to be constrained. + template<typename _Dummy> using _TCC = + _TC<is_same<_Dummy, void>::value, _T1, _T2>; + + template<typename _Dummy = void, typename + enable_if<_TCC<_Dummy>::template + _ConstructibleTuple<_T1, _T2>() + && _TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_T1, _T2>(), + bool>::type = true> + constexpr tuple(const _T1& __a1, const _T2& __a2) + : _Inherited(__a1, __a2) { } + + template<typename _Dummy = void, typename + enable_if<_TCC<_Dummy>::template + _ConstructibleTuple<_T1, _T2>() + && !_TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_T1, _T2>(), + bool>::type = false> + explicit constexpr tuple(const _T1& __a1, const _T2& __a2) + : _Inherited(__a1, __a2) { } + + // Shortcut for the cases where constructors taking _U1, _U2 + // need to be constrained. + using _TMC = _TC<true, _T1, _T2>; + + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> constexpr tuple(_U1&& __a1, _U2&& __a2) : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit constexpr tuple(_U1&& __a1, _U2&& __a2) + : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } + constexpr tuple(const tuple&) = default; constexpr tuple(tuple&&) = default; - template<typename _U1, typename _U2, typename = typename - enable_if<__and_<is_convertible<const _U1&, _T1>, - is_convertible<const _U2&, _T2>>::value>::type> + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _ConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = true> constexpr tuple(const tuple<_U1, _U2>& __in) : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { } - template<typename _U1, typename _U2, typename = typename - enable_if<__and_<is_convertible<_U1, _T1>, - is_convertible<_U2, _T2>>::value>::type> + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _ConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit constexpr tuple(const tuple<_U1, _U2>& __in) + : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { } + + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> constexpr tuple(tuple<_U1, _U2>&& __in) : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } - template<typename _U1, typename _U2, typename = typename - enable_if<__and_<is_convertible<const _U1&, _T1>, - is_convertible<const _U2&, _T2>>::value>::type> + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit constexpr tuple(tuple<_U1, _U2>&& __in) + : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } + + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _ConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = true> constexpr tuple(const pair<_U1, _U2>& __in) : _Inherited(__in.first, __in.second) { } - template<typename _U1, typename _U2, typename = typename - enable_if<__and_<is_convertible<_U1, _T1>, - is_convertible<_U2, _T2>>::value>::type> + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _ConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit constexpr tuple(const pair<_U1, _U2>& __in) + : _Inherited(__in.first, __in.second) { } + + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> constexpr tuple(pair<_U1, _U2>&& __in) : _Inherited(std::forward<_U1>(__in.first), std::forward<_U2>(__in.second)) { } + template<typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit constexpr tuple(pair<_U1, _U2>&& __in) + : _Inherited(std::forward<_U1>(__in.first), + std::forward<_U2>(__in.second)) { } + // Allocator-extended constructors. template<typename _Alloc> tuple(allocator_arg_t __tag, const _Alloc& __a) : _Inherited(__tag, __a) { } - template<typename _Alloc> + template<typename _Alloc, typename _Dummy = void, + typename enable_if< + _TCC<_Dummy>::template + _ConstructibleTuple<_T1, _T2>() + && _TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_T1, _T2>(), + bool>::type=true> + tuple(allocator_arg_t __tag, const _Alloc& __a, const _T1& __a1, const _T2& __a2) : _Inherited(__tag, __a, __a1, __a2) { } - template<typename _Alloc, typename _U1, typename _U2> + template<typename _Alloc, typename _Dummy = void, + typename enable_if< + _TCC<_Dummy>::template + _ConstructibleTuple<_T1, _T2>() + && !_TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_T1, _T2>(), + bool>::type=false> + + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const _T1& __a1, const _T2& __a2) + : _Inherited(__tag, __a, __a1, __a2) { } + + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> tuple(allocator_arg_t __tag, const _Alloc& __a, _U1&& __a1, _U2&& __a2) : _Inherited(__tag, __a, std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + _U1&& __a1, _U2&& __a2) + : _Inherited(__tag, __a, std::forward<_U1>(__a1), + std::forward<_U2>(__a2)) { } + template<typename _Alloc> tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) : _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { } @@ -664,28 +992,92 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } - template<typename _Alloc, typename _U1, typename _U2> + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _ConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = true> tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple<_U1, _U2>& __in) : _Inherited(__tag, __a, static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { } - template<typename _Alloc, typename _U1, typename _U2> + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _ConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const tuple<_U1, _U2>& __in) + : _Inherited(__tag, __a, + static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) + { } + + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in) : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } - template<typename _Alloc, typename _U1, typename _U2> + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + tuple<_U1, _U2>&& __in) + : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) + { } + + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _ConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = true> tuple(allocator_arg_t __tag, const _Alloc& __a, const pair<_U1, _U2>& __in) : _Inherited(__tag, __a, __in.first, __in.second) { } - template<typename _Alloc, typename _U1, typename _U2> + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _ConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const pair<_U1, _U2>& __in) + : _Inherited(__tag, __a, __in.first, __in.second) { } + + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in) : _Inherited(__tag, __a, std::forward<_U1>(__in.first), std::forward<_U2>(__in.second)) { } + template<typename _Alloc, typename _U1, typename _U2, typename + enable_if<_TMC::template + _MoveConstructibleTuple<_U1, _U2>() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + pair<_U1, _U2>&& __in) + : _Inherited(__tag, __a, std::forward<_U1>(__in.first), + std::forward<_U2>(__in.second)) { } + tuple& operator=(const tuple& __in) { diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc new file mode 100644 index 0000000..50edda9 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc @@ -0,0 +1,108 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2015 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/>. + +#include <utility> + +struct Explicit +{ + Explicit() = default; + explicit Explicit(int) {} +}; + +std::pair<int, int> f1() {return {1,2};} + +std::pair<Explicit, Explicit> f2() {return {1,2};} // { dg-error "explicit" } + +std::pair<long, long> f3() {return std::pair<int, int>{1,2};} + +std::pair<Explicit, Explicit> f4() +{ + return std::pair<int, int>{1,2}; // { dg-error "could not convert" } +} + +std::pair<long, long> f5() {return {1,2};} + +std::pair<int, int> v0{1,2}; + +std::pair<Explicit, Explicit> v1{1,2}; + +std::pair<Explicit, Explicit> v2 = {1,2}; // { dg-error "explicit" } + +std::pair<Explicit, Explicit> v3{std::pair<int,int>{1,2}}; + +std::pair<Explicit, Explicit> v4 = + std::pair<int,int>{1,2}; // { dg-error "conversion" } + +std::pair<char *, char *> v5(0,0); + +std::pair<long, long> v6{1,2}; + +std::pair<long, long> v7 = {1,2}; + +std::pair<long, long> v8{std::pair<int,int>{1,2}}; + +std::pair<long, long> v9 = std::pair<int,int>{1,2}; + +std::pair<Explicit, Explicit> v10{v0}; + +std::pair<Explicit, Explicit> v11 = v0; // { dg-error "conversion" } + +std::pair<long, long> v12{v0}; + +std::pair<long, long> v13 = v0; + +void f6(std::pair<Explicit, Explicit>) {} + +void f7(std::pair<long, long>) {} + +void test_arg_passing() +{ + f6(v0); // { dg-error "could not convert" } + f6(v1); + f6({1,2}); // { dg-error "explicit" } + f6(std::pair<Explicit, Explicit>{}); + f6(std::pair<int, int>{}); // { dg-error "could not convert" } + f7(v0); + f7(v6); + f7({1,2}); + f7(std::pair<int, int>{}); + f7(std::pair<long, long>{}); +} + +struct MoveOnly +{ + MoveOnly() = default; + MoveOnly(MoveOnly&&) {} +}; + +struct ExplicitMoveOnly +{ + ExplicitMoveOnly() = default; + ExplicitMoveOnly(ExplicitMoveOnly&&) {} + explicit ExplicitMoveOnly(MoveOnly&&) {} +}; + +std::pair<int*, ExplicitMoveOnly> v14{0, MoveOnly{}}; +std::pair<ExplicitMoveOnly, int*> v15{MoveOnly{}, 0}; + +std::pair<int*, ExplicitMoveOnly> v16 = + {0, MoveOnly{}}; // { dg-error "explicit" } +std::pair<ExplicitMoveOnly, int*> v17 = + {MoveOnly{}, 0}; // { dg-error "explicit" } diff --git a/libstdc++-v3/testsuite/20_util/pair/piecewise.cc b/libstdc++-v3/testsuite/20_util/pair/piecewise.cc index bcdab7d..40ab16b 100644 --- a/libstdc++-v3/testsuite/20_util/pair/piecewise.cc +++ b/libstdc++-v3/testsuite/20_util/pair/piecewise.cc @@ -69,20 +69,20 @@ void test01() { bool test __attribute__((unused)) = true; - std::pair<type_one, type_zero> pp0(std::piecewise_construct_t(), + std::pair<type_one, type_zero> pp0(std::piecewise_construct, std::forward_as_tuple(-3), std::forward_as_tuple()); VERIFY( pp0.first.get() == -3 ); VERIFY( pp0.second.get() == 757 ); - std::pair<type_one, type_two> pp1(std::piecewise_construct_t(), + std::pair<type_one, type_two> pp1(std::piecewise_construct, std::forward_as_tuple(6), std::forward_as_tuple(5, 4)); VERIFY( pp1.first.get() == 6 ); VERIFY( pp1.second.get1() == 5 ); VERIFY( pp1.second.get2() == 4 ); - std::pair<type_two, type_two> pp2(std::piecewise_construct_t(), + std::pair<type_two, type_two> pp2(std::piecewise_construct, std::forward_as_tuple(2, 1), std::forward_as_tuple(-1, -3)); VERIFY( pp2.first.get1() == 2 ); diff --git a/libstdc++-v3/testsuite/20_util/pair/requirements/dr2367.cc b/libstdc++-v3/testsuite/20_util/pair/requirements/dr2367.cc new file mode 100644 index 0000000..603b7c5 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/requirements/dr2367.cc @@ -0,0 +1,41 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2015 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/>. + +#include <utility> +#include <type_traits> + +// DR 2367, pair and tuple are not correctly implemented for is_constructible with no args +void test_default_constructible() +{ + struct X + { + X() = delete; + }; + + typedef std::pair<int, X> P; + static_assert(!std::is_constructible<P>::value, ""); + static_assert(!std::is_default_constructible<P>::value, ""); +} + +int main() +{ + test_default_constructible(); + return 0; +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/explicit_construct.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/explicit_construct.cc new file mode 100644 index 0000000..114a490 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/explicit_construct.cc @@ -0,0 +1,282 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2015 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/>. + +#include <tuple> +#include <utility> +#include <memory> + +struct Explicit +{ + Explicit() = default; + explicit Explicit(int) {} +}; + +std::tuple<int> f1a() {return {1};} +std::tuple<int, int> f1b() {return {1,2};} +std::tuple<int, int, int> f1c() {return {1,2,3};} + +std::tuple<Explicit> f2_a() {return {1};} // { dg-error "explicit" } +std::tuple<Explicit, Explicit> f2_b() {return {1,2};} // { dg-error "explicit" } +std::tuple<Explicit, Explicit, Explicit> f2_c() {return {1,2,3};} // { dg-error "explicit" } + +std::tuple<long> f3_a() {return std::tuple<int>{1};} +std::tuple<long, long> f3_b() {return std::tuple<int, int>{1,2};} +std::tuple<long, long, long> f3_c() {return std::tuple<int, int, int>{1,2,3};} + +std::tuple<Explicit> f4_a() +{ + return std::tuple<int>{1}; // { dg-error "could not convert" } +} +std::tuple<Explicit, Explicit> f4_b() +{ + return std::tuple<int, int>{1,2}; // { dg-error "could not convert" } +} +std::tuple<Explicit, Explicit, Explicit> f4_c() +{ + return std::tuple<int, int,int>{1,2,3}; // { dg-error "could not convert" } +} + +std::tuple<long> f5_a() {return {1};} +std::tuple<long, long> f5_b() {return {1,2};} +std::tuple<long, long, long> f5_c() {return {1,2,3};} + +std::tuple<int, int> fp1() {return std::pair<int, int>{1,2}; } +std::tuple<long, long> fp2() {return std::pair<int, int>{1,2}; } +std::tuple<Explicit, Explicit> fp3() + {return std::pair<int, int>{1,2}; } // { dg-error "could not convert" } + +std::tuple<int> v0_a{1}; +std::tuple<int, int> v0_b{1,2}; +std::tuple<int, int, int> v0_c{1,2,3}; + +std::tuple<Explicit> v1_a{1}; +std::tuple<Explicit, Explicit> v1_b{1,2}; +std::tuple<Explicit, Explicit, Explicit> v1_c{1,2,3}; + +std::tuple<Explicit> v2_a = {1}; // { dg-error "explicit" } +std::tuple<Explicit, Explicit> v2_b = {1,2}; // { dg-error "explicit" } +std::tuple<Explicit, Explicit, Explicit> v2_c = {1,2,3}; // { dg-error "explicit" } + +std::tuple<Explicit> v3_a{std::tuple<int>{1}}; +std::tuple<Explicit, Explicit> v3_b{std::tuple<int,int>{1,2}}; +std::tuple<Explicit, Explicit, Explicit> v3_c{std::tuple<int,int,int>{1,2,3}}; + +std::tuple<Explicit, Explicit> v4_a = + std::tuple<int>{1}; // { dg-error "conversion" } +std::tuple<Explicit, Explicit> v4_b = + std::tuple<int,int>{1,2}; // { dg-error "conversion" } +std::tuple<Explicit, Explicit, Explicit> v4_c = + std::tuple<int,int,int>{1,2,3}; // { dg-error "conversion" } + +std::tuple<long> v6_a{1}; +std::tuple<long, long> v6_b{1,2}; +std::tuple<long, long, long> v6_c{1,2,3}; + +std::tuple<long> v7_a = {1}; +std::tuple<long, long> v7_b = {1,2}; +std::tuple<long, long, long> v7_c = {1,2,3}; + +std::tuple<long> v8_a{std::tuple<int>{1}}; +std::tuple<long, long> v8_b{std::tuple<int,int>{1,2}}; +std::tuple<long, long, long> v8_c{std::tuple<int,int,int>{1,2,3}}; + +std::tuple<long> v9_a = std::tuple<int>{1}; +std::tuple<long, long> v9_b = std::tuple<int,int>{1,2}; +std::tuple<long, long, long> v9_c = std::tuple<int,int,int>{1,2,3}; + +std::tuple<Explicit> v10_a{v0_a}; +std::tuple<Explicit, Explicit> v10_b{v0_b}; +std::tuple<Explicit, Explicit, Explicit> v10_c{v0_c}; + +std::tuple<Explicit> v11_a = v0_a; // { dg-error "conversion" } +std::tuple<Explicit, Explicit> v11_b = v0_b; // { dg-error "conversion" } +std::tuple<Explicit, Explicit, Explicit> v11_c + = v0_c; // { dg-error "conversion" } + +std::tuple<long> v12_a{v0_a}; +std::tuple<long, long> v12_b{v0_b}; +std::tuple<long, long, long> v12_c{v0_c}; + +std::tuple<long> v13_a = v0_a; +std::tuple<long, long> v13_b = v0_b; +std::tuple<long, long, long> v13_c = v0_c; + +std::tuple<int, int> v14{std::pair<int, int>{1,2}}; +std::tuple<long, long> v15{std::pair<int, int>{1,2}}; +std::tuple<Explicit, Explicit> v16{std::pair<int, int>{1,2}}; + +std::tuple<int, int> v17 = std::pair<int, int>{1,2}; +std::tuple<long, long> v18 = std::pair<int, int>{1,2}; +std::tuple<Explicit, Explicit> v19 + = std::pair<int, int>{1,2}; // { dg-error "conversion" } + +std::pair<int, int> v20; + +std::tuple<int, int> v21{v20}; +std::tuple<long, long> v22{v20}; +std::tuple<Explicit, Explicit> v23{v20}; + +std::tuple<int, int> v24 = v20; +std::tuple<long, long> v25 = v20; +std::tuple<Explicit, Explicit> v26 = v20; // { dg-error "conversion" } + +std::tuple<int> v27_a{std::allocator_arg, std::allocator<int>{}, 1}; +std::tuple<int, int> v27_b{std::allocator_arg, std::allocator<int>{}, 1, 2}; +std::tuple<int, int, int> v27_c{std::allocator_arg, std::allocator<int>{}, 1,2,3}; + +std::tuple<long> v28_a{std::allocator_arg, std::allocator<int>{}, 1}; +std::tuple<long, long> v28_b{std::allocator_arg, std::allocator<int>{}, 1, 2}; +std::tuple<long, long, long> + v28_c{std::allocator_arg, std::allocator<int>{}, 1,2,3}; + +std::tuple<Explicit> v29_a{std::allocator_arg, std::allocator<int>{}, 1}; +std::tuple<Explicit, Explicit> + v29_b{std::allocator_arg, std::allocator<int>{}, 1, 2}; +std::tuple<Explicit, Explicit, Explicit> + v29_c{std::allocator_arg, std::allocator<int>{}, 1,2,3}; + +std::tuple<int> v30_a = {std::allocator_arg, std::allocator<int>{}, 1}; +std::tuple<int, int> v30_b = {std::allocator_arg, std::allocator<int>{}, 1, 2}; +std::tuple<int, int, int> v30_c + = {std::allocator_arg, std::allocator<int>{}, 1,2,3}; + +std::tuple<long> v31_a = {std::allocator_arg, std::allocator<int>{}, 1}; +std::tuple<long, long> v31_b = {std::allocator_arg, std::allocator<int>{}, 1, 2}; +std::tuple<long, long, long> + v31_c{std::allocator_arg, std::allocator<int>{}, 1,2,3}; + +std::tuple<Explicit> v32_a + = {std::allocator_arg, std::allocator<int>{}, 1}; // { dg-error "explicit" } +std::tuple<Explicit, Explicit> v32_b + = {std::allocator_arg, std::allocator<int>{}, 1, 2}; // { dg-error "explicit" } +std::tuple<Explicit, Explicit, Explicit> v32_c + = {std::allocator_arg, std::allocator<int>{}, 1,2,3}; // { dg-error "explicit" } + +std::tuple<int, int> v33{std::allocator_arg, std::allocator<int>{}, + std::pair<int, int>{1, 2}}; + +std::tuple<long, long> v34{std::allocator_arg, std::allocator<int>{}, + std::pair<int, int>{1, 2}}; + +std::tuple<Explicit, Explicit> + v35{std::allocator_arg, std::allocator<int>{}, std::pair<int, int>{1, 2}}; + +std::tuple<int, int> v36 = {std::allocator_arg, std::allocator<int>{}, + std::pair<int, int>{1, 2}}; + +std::tuple<long, long> v37 = {std::allocator_arg, std::allocator<int>{}, + std::pair<int, int>{1, 2}}; + +std::tuple<Explicit, Explicit> v38 += {std::allocator_arg, std::allocator<int>{}, std::pair<int, int>{1, 2}}; // { dg-error "explicit" } + +std::tuple<int, int> v39{std::allocator_arg, std::allocator<int>{}, v20}; + +std::tuple<long, long> v40{std::allocator_arg, std::allocator<int>{}, v20}; + +std::tuple<Explicit, Explicit> + v41{std::allocator_arg, std::allocator<int>{}, v20}; + +std::tuple<int, int> v42 = {std::allocator_arg, std::allocator<int>{}, v20}; + +std::tuple<long, long> v43 = {std::allocator_arg, std::allocator<int>{}, v20}; + +std::tuple<Explicit, Explicit> v44 += {std::allocator_arg, std::allocator<int>{}, v20}; // { dg-error "explicit" } + +struct DeletedCopy +{ + DeletedCopy(int); + DeletedCopy(const DeletedCopy&) = delete; +}; + +std::tuple<DeletedCopy> v45{42}; +std::tuple<DeletedCopy> v46{std::allocator_arg, + std::allocator<DeletedCopy>{}, 42}; + +struct Sanity +{ + int v; +}; + +std::tuple<int, Sanity> v47(3, {42}); +std::tuple<int, int, Sanity> v48(3, 4, {42}); +std::tuple<int, Sanity> v49(std::allocator_arg, + std::allocator<Sanity>{}, + 3, {42}); +std::tuple<int, int, Sanity> v50(std::allocator_arg, + std::allocator<Sanity>{}, + 3, 4, {42}); + +void f6_a(std::tuple<Explicit>) {} +void f6_b(std::tuple<Explicit, Explicit>) {} +void f6_c(std::tuple<Explicit, Explicit, Explicit>) {} + +void f7_a(std::tuple<long>) {} +void f7_b(std::tuple<long, long>) {} +void f7_c(std::tuple<long, long, long>) {} + +void test_arg_passing() +{ + f6_a(v0_a); // { dg-error "could not convert" } + f6_b(v0_b); // { dg-error "could not convert" } + f6_c(v0_c); // { dg-error "could not convert" } + f6_b(v20); // { dg-error "could not convert" } + + f6_a(v1_a); + f6_b(v1_b); + f6_c(v1_c); + + f6_a({1}); // { dg-error "explicit" } + f6_b({1,2}); // { dg-error "explicit" } + f6_c({1,2,3}); // { dg-error "explicit" } + + f6_a(std::tuple<Explicit>{}); + f6_b(std::tuple<Explicit, Explicit>{}); + f6_c(std::tuple<Explicit, Explicit, Explicit>{}); + + f6_a(std::tuple<int>{}); // { dg-error "could not convert" } + f6_b(std::tuple<int, int>{}); // { dg-error "could not convert" } + f6_c(std::tuple<int, int, int>{}); // { dg-error "could not convert" } + f6_b(std::pair<int, int>{}); // { dg-error "could not convert" } + + f7_a(v0_a); + f7_b(v0_b); + f7_c(v0_c); + f7_b(v20); + + f7_a(v6_a); + f7_b(v6_b); + f7_c(v6_c); + + f7_a({1}); + f7_b({1,2}); + f7_c({1,2,3}); + + f7_a(std::tuple<int>{}); + f7_b(std::tuple<int, int>{}); + f7_c(std::tuple<int, int, int>{}); + f7_b(std::pair<int, int>{}); + + + f7_a(std::tuple<long>{}); + f7_b(std::tuple<long, long>{}); + f7_c(std::tuple<long, long, long>{}); +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/requirements/dr2367.cc b/libstdc++-v3/testsuite/20_util/tuple/requirements/dr2367.cc new file mode 100644 index 0000000..d3b975b --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/requirements/dr2367.cc @@ -0,0 +1,47 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2015 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/>. + +#include <tuple> +#include <type_traits> + +// DR 2367, pair and tuple are not correctly implemented for is_constructible with no args +void test_default_constructible() +{ + struct X + { + X() = delete; + }; + + typedef std::tuple<int, X> T; + static_assert(!std::is_constructible<T>::value, ""); + static_assert(!std::is_default_constructible<T>::value, ""); + + typedef std::tuple<int, int, X> T2; + static_assert(!std::is_constructible<T2>::value, ""); + static_assert(!std::is_default_constructible<T2>::value, ""); + + +} + +int main() +{ + test_default_constructible(); + return 0; +}