我有以下代码。
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));
哪个编译器抱怨
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));
为什么编译器会将元组中第一个元素的类型推断为const char(&amp;&amp;)[5]?
答案 0 :(得分:2)
一般来说,为了使演绎成功,参数需要与参数具有相同的一般形式。有一些例外情况可以从T &&
推断U &
(通过选择T = U &
),但没有为此案例指定此类例外。
14.8.2.5从类型[temp.deduct.type]中扣除模板参数
8如果
T
和TT
,可以推导出模板类型参数i
,模板模板参数P
或模板非类型参数A
有下列形式之一:[...]
T&
T&&
[...]
它不完全清楚,但这要求P
(参数)和A
(参数)都具有相同的形式。它们都需要T&
形式,或两者都是T&&
形式。例外情况,T &&
可以从U &
推断T &&
的情况是通过在匹配发生之前将T
更改为普通P
来完成的,在有限的情况下:
10同样,如果
(T)
的表单包含Pi
,那么{{>参数类型列表的每个参数类型P
Ai
1}}与A
的相应参数类型列表的相应参数类型P
进行比较。如果A
和Pi
是在获取函数模板的地址(14.8.2.2)时或从函数声明(14.8.2.6)和{{1中推导出模板参数时 - 来自演绎的函数类型和Ai
分别是P
和A
的顶级参数类型列表的参数,Pi
如果是Ai
则会调整rvalue对cv-unqualified模板参数的引用和Pi
是左值引用,在这种情况下,T&&
的类型被更改为模板参数类型(即,T
更改为只需P
)。 [...]
和
14.8.2.1从函数调用中减去模板参数[temp.deduct.call]
3 [...]如果
A
是对cv-nonqualified模板参数的右值引用,并且参数是左值,则类型&#34;左值引用A
&#34 ;用于代替template <typename T> struct S { }; template <typename T> void f(S<const T>) { } int main() { f(S<void()>()); }
进行类型扣除。 [...]
但没有类似的例外适用于您的方案。
呈现
的原理相同const T
无效:void()
无法从T = void()
推断出来,即使f<void()>
会给出确切的结果,并且调用template <typename... Types> // vv-- change here
void print_tuple(const std::tuple<Types...>& value)
也会成功。
Wintermute的删除答案显示您可以使用
Types
相反:这允许value
被推导为左值引用,rvalue引用或非引用,具体取决于{{1}}的类型。
答案 1 :(得分:0)
您是否打算在&&
中使用std::tuple<Types&&...>
作为通用参考?这不是普遍的参考;它是rvalue引用,只能绑定到rvalues。您可以这样做以检查它是什么类型的引用:
template<typename T>
class TD;
然后定义模板功能:
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;
}
然后您将看到编译错误,如:
implicit instantiation of undefined template 'TD<const std::__1::tuple<std::__1::basic_string<char> &&, int &&> &>'
您甚至可以看到int
类型,它推导为右值参考。 Rvalue引用不能绑定到左值。你可以通过调用:
int i = 1;
print_tuple(std::forward_as_tuple(i,1)); // error.
因此,推导const char(&&)[5]
是正确的,并且字符串文字无法转换为const char(&&)[5]
。如果您致电print_tuple
,请致电:
print_tuple(std::forward_as_tuple(string("test"),1));
它会起作用。现在类型为tuple<string&&, int&&>
。