I have the following code.
template <typename... Types>
void print_tuple(const std::tuple<Types&&...>& value)
{
std::cout << std::get<0>(value) << "," << std::get<1>(value) << std::endl;
}
print_tuple(std::forward_as_tuple("test",1));
which compiler complains about
error: invalid initialization of reference of type ‘const std::tuple<const char (&&)[5], int&&>&’ from expression of type ‘std::tuple<const char (&)[5], int&&>’
print_tuple(std::forward_as_tuple("test",1));
why does compiler deduce the type of the first element in the tuple to be const char (&&)[5]?
Generally speaking, for deduction to succeed, the argument needs to have the same general form as the parameter. There are some exceptions where T &&
can be deduced from U &
(by selecting T = U &
), but no such exception was specified for this case.
14.8.2.5 Deducing template arguments from a type [temp.deduct.type]
8 A template type argument
T
, a template template argumentTT
or a template non-type argumenti
can be deduced ifP
andA
have one of the following forms:[...]
T&
T&&
[...]
It's not exactly clear, but this requires P
(the parameter) and A
(the argument) to both have the same form. They need to both be of the T&
form, or both of the T&&
form. The exceptions, the circumstances where T &&
can be deduced from U &
, are done by changing T &&
to plain T
before the matching takes place, in limited circumstances:
10 Similarly, if
P
has a form that contains(T)
, then each parameter typeP i
of the respective parameter-type-list ofP
is compared with the corresponding parameter typeA i
of the corresponding parameter-type-list ofA
. IfP
andA
are function types that originated from deduction when taking the address of a function template (14.8.2.2) or when deducing template arguments from a function declaration (14.8.2.6) andP i
andA i
are parameters of the top-level parameter-type-list ofP
andA
, respectively,P i
is adjusted if it is an rvalue reference to a cv-unqualified template parameter andA i
is an lvalue reference, in which case the type ofP i
is changed to be the template parameter type (ie,T&&
is changed to simplyT
). [...]
and
14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]
3 [...] If
P
is an rvalue reference to a cv-unqualified template parameter and the argument is an lvalue, the type "lvalue reference toA
" is used in place ofA
for type deduction. [...]
but no similar exception applies to your scenario.
It's this same principle that renders
template <typename T> struct S { };
template <typename T> void f(S<const T>) { }
int main() { f(S<void()>()); }
invalid: const T
cannot be deduced from void()
, even though T = void()
would give exactly that result, and calling f<void()>
would succeed.
Wintermute's deleted answer showed that you can use
template <typename... Types> // vv-- change here void print_tuple(const std::tuple<Types...>& value)
instead: this allows Types
to be deduced as lvalue references, as rvalue references, or as non-references, depending on the type of value
.
Did you intend to use &&
in std::tuple<Types&&...>
as a universal reference? This is not universal reference; it is rvalue reference and can only bind to rvalues. You can do like this to check what kind of reference it is:
template<typename T>
class TD;
Then define your template function:
template <typename... Types>
void print_tuple(const std::tuple<Types&&...>& value)
{
TD<decltype(value)> a;
std::cout << std::get<0>(value) << "," << std::get<1>(value) << std::endl;
}
Then you will see the compilation error like:
implicit instantiation of undefined template 'TD<const std::__1::tuple<std::__1::basic_string<char> &&, int &&> &>'
You can see that even for the int
type, it deduces to be rvalue reference. Rvalue references cannot bind to lvalues. You can try that by calling:
int i = 1;
print_tuple(std::forward_as_tuple(i,1)); // error.
Therefore, it is correct that const char(&&)[5]
is deduced, and a string literal cannot be converted to const char(&&)[5]
. If you call print_tuple
like:
print_tuple(std::forward_as_tuple(string("test"),1));
It will work. Now the type is tuple<string&&, int&&>
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.