Per [tuple.cnstr]/6:
EXPLICIT constexpr tuple();
Effects: Value-initializes each element.
Remarks: This constructor shall not participate in overload resolution unless
is_default_constructible_v<Ti>
is true for all i. [ Note: This behavior can be implemented by a constructor template with default template arguments. — end note ] The constructor is explicit if and only ifTi
is not implicitly default-constructible for at least one i. [ Note: This behavior can be implemented with a trait that checks whether aconst Ti&
can be initialized with{}
. — end note ]
Therefore, the following code
#include <tuple>
struct A {
explicit A() = default;
};
int main()
{
[[maybe_unused]] std::tuple<A> x = {};
}
is ill-formed because the default constructor of std::tuple<A>
is explicit. GCC 9.1.0 correctly raises an error. However, it compiles fine on Clang 8.0.0.
Here's the relevant code from libc++:
template <class ..._Args>
static constexpr bool __enable_default() {
return __all<is_default_constructible<_Args>::value...>::value;
}
And the constructor:
template <bool _Dummy = true, class = typename enable_if<
_CheckArgsConstructor<_Dummy>::template __enable_default<_Tp...>()
>::type>
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR tuple()
_NOEXCEPT_(__all<is_nothrow_default_constructible<_Tp>::value...>::value) {}
It seems that libc++ didn't even think of implementing this. Is my understanding correct that this is a bug?