As part of a bigger project, I'm playing with std::tuple
and templates; consider the following code:
template <typename ...T> void foo(tuple<T...> t) {}
void bar(tuple<int, char> t) {}
tuple<int, char> quxx() { return {1, 'S'}; }
int main(int argc, char const *argv[])
{
foo({1, 'S'}); // error
foo(make_tuple(1, 'S')); // ok
bar({1, 'S'}); // ok
quxx(); // ok
return 0;
}
According to this answer C++17 supports tuple initialization from copy-list-initialization, however it seems such support is limited since I get the following error (GCC 7.2.0):
main.cpp: In function 'int main(int, const char**)':
main.cpp:14:17: error: could not convert '{1, 'S'}' from '<brace-enclosed initializer list>' to 'std::tuple<>'
foo({1, 'S'}); // error
^
Is there any way I can use brace-enclosed syntax in this scenario?
Some Context : this is going to be used in an operator overload so I guess I'm bound to tuples and cannot make use of variadics, any hint is well-accepted.
Extra : Clang 6 also complains
prog.cc:12:5: error: no matching function for call to 'foo'
foo({1, 'S'}); // error
^~~
prog.cc:6:31: note: candidate function [with T = <>] not viable: cannot convert initializer list argument to 'tuple<>'
template <typename ...T> void foo(tuple<T...> t) {}
A braced-init-list, like {1, 'S'}
, does not actually have a type. In the context of template deduction, you can only use them in certain cases - when deducing against initializer_list<T>
(where T
is a function template parameter) or when the corresponding parameter is already deduced by something else. In this case, neither of those two things is true - so the compiler cannot figure out what ...T
is supposed to be.
So you can provide the types directly:
foo<int, char>({1, 'S'});
Or you can construct the tuple
yourself and pass that in:
foo(std::tuple<int, char>(1, 'S')); // most explicit
foo(std::tuple(1, 'S')); // via class template argument deduction
Today, ClassTemplate<Ts...>
can only be deduced from expressions of type ClassTemplate<Us...>
or types that inherit from something like that. A hypothetical proposal could extend that to additionally try to perform class template argument deduction on the expression to see if that deduction succeeds. In this case, {1, 'S'}
isn't a tuple<Ts...>
but tuple __var{1, 'S'}
does successfully deduce tuple<int, char>
so that would work. Such a proposal would also have to address issues like... what if we're deducing ClassTemplate<T, Ts...>
or any minor variation, which isn't something that class template argument deduction allows (but is something that many people have at times expressed interest in being able to do).
I'm not aware of such a proposal today.