Why the current attempts fail
std::tie(a, b)
produces a std::tuple<int&, string&>
.
This type is not related to std::tuple<int, string>
etc.
std::tuple<T...>
s have several assignment-operators:
- A default assignment-operator, that takes a
std::tuple<T...>
- A tuple-converting assignment-operator template with a type parameter pack
U...
, that takes astd::tuple<U...>
- A pair-converting assignment-operator template with two type parameters
U1, U2
, that takes astd::pair<U1, U2>
For those three versions exist copy- and move-variants; add either a const&
or a &&
to the types they take.
The assignment-operator templates have to deduce their template arguments from the function argument type (i.e. of the type of the RHS of the assignment-expression).
Without a conversion operator in Foo
, none of those assignment-operators are viable for std::tie(a,b) = foo
.
If you add a conversion operator to Foo
,
then only the default assignment-operator becomes viable:
Template type deduction does not take user-defined conversions into account.
That is, you cannot deduce template arguments for the assignment-operator templates from the type Foo
.
Since only one user-defined conversion is allowed in an implicit conversion sequence, the type the conversion operator converts to must match the type of the default assignment operator exactly. That is, it must use the exact same tuple element types as the result of std::tie
.
To support conversions of the element types (e.g. assignment of Foo::a
to a long
), the conversion operator of Foo
has to be a template:
struct Foo {
int a;
string b;
template<typename T, typename U>
operator std::tuple<T, U>();
};
However, the element types of std::tie
are references.
Since you should not return a reference to a temporary,
the options for conversions inside the operator template are quite limited
(heap, type punning, static, thread local, etc).