I have a class with copy & move ctor deleted.
struct A
{
A(int a):data(a){}
~A(){ std::cout << \"~A()\" << this << \" : \" <<
This is bad:
auto q = std::tuple(A{100},A{200});
you are constructing a tuple of rvalue references to temporaries that get destroyed at the end of the expression, so you're left with dangling references.
The correct statement would be:
std::tuple q(100, 200);
However, until quite recently, the above was not supported by the standard. In N4296, the wording around the relevant constructor for tuple is [tuple.cnstr]:
templateconstexpr explicit tuple(UTypes&&... u); Requires:
sizeof...(Types) == sizeof...(UTypes).is_constructibleis true for all::value i.
Effects: Initializes the elements in the tuple with the corresponding value instd::forward.(u)
Remark: This constructor shall not participate in overload resolution unless each type inUTypesis implicitly convertible to its corresponding type inTypes.
So, this constructor was not participating in overload resolution because int is not implicitly convertible to A. This has been resolved by the adoption of Improving pair and tuple, which addressed precisely your use-case:
struct D { D(int); D(const D&) = delete; };
std::tuple td(12); // Error
The new wording for this constructor is, from N4527:
Remarks: This constructor shall not participate in overload resolution unless
sizeof...(Types) >= 1andis_constructibleis true for all::value i. The constructor is explicit if and only ifis_convertibleis::value falsefor at least one i.
And is_constructible::value is true.
To present the difference another way, here is an extremely stripped down tuple implementation:
struct D { D(int ) {} D(const D& ) = delete; };
template
struct Tuple {
Tuple(const T& t)
: T(t)
{ }
template ::value>
#else
typename = std::enable_if_t::value>
#endif
>
Tuple(U&& u)
: t(std::forward(u))
{ }
T t;
};
int main()
{
Tuple t(12);
}
If USE_OLD_RULES is defined, the first constructor is the only viable constructor and hence the code will not compile since D is noncopyable. Otherwise, the second constructor is the best viable candidate and that one is well-formed.
The adoption was recent enough that neither gcc 5.2 nor clang 3.6 actually will compile this example yet. So you will either need a newer compiler than that (gcc 6.0 works) or come up with a different design.