On Sun, 7 Jun 2015, Ville Voutilainen wrote:
- explicit
- constexpr tuple(const _Elements&... __elements)
+ template<typename... _UElements, typename
+ enable_if<__and_<is_same<const _Elements&,
+ const _UElements&>...>::value
+ && _TC<(sizeof...(_Elements) == sizeof...(_UElements)),
+ _Elements...>::template
+ _ConstructibleTuple<_UElements...>()
+ && _TC<(sizeof...(_Elements) == sizeof...(_UElements)),
+ _Elements...>::template
+ _ImplicitlyConvertibleTuple<_UElements...>()
+ && !_TC<(sizeof...(_Elements) == sizeof...(_UElements)),
+ _Elements...>::template
+ _MoveConstructibleTuple<_UElements...>()
+ && !_TC<(sizeof...(_Elements) == sizeof...(_UElements)),
+ _Elements...>::template
+ _ImplicitlyMoveConvertibleTuple<_UElements...>()
+ && (sizeof...(_Elements) >= 1),
+ bool>::type=true>
+ constexpr tuple(const _UElements&... __elements)
: _Inherited(__elements...) { }
Since the paper does not mention looking at _MoveConstructibleTuple or
_ImplicitlyMoveConvertibleTuple here, could you add a comment explaining
why that is needed?
Does the following code still compile with your patch?
struct A { int a,b; };
std::tuple<int,int,A> a(3,4,{1,2});
IMO the parts with is_default_constructible point to a core issue, we
should not have to duplicate information, especially in such a convoluted
way. But I guess that has lower priority than noexcept(auto), and I
haven't yet looked if concepts will help.
You use a lot: typename enable_if<X, bool>::type=true
while the current code seems to favor: class=typename enable_if<X>::type.
I don't really care which one is used, but it is easier to read when the
style is consistent through the library.
Introducing
typename _XXX = _TC<(sizeof...(_Elements) == sizeof...(_UElements)),
_Elements...>
and then using _XXX::template thing() might give less clutter when you
have to repeat it 4 times.
--
Marc Glisse