简体   繁体   English

推导出c ++ 11中元组元素的类型

[英]deduce the type of tuple elements in c++11

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]? 为什么编译器会将元组中第一个元素的类型推断为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. 有一些例外,其中T &&可以从U &推导出(通过选择T = U & ),但没有为此案例指定此类例外。

14.8.2.5 Deducing template arguments from a type [temp.deduct.type] 14.8.2.5从类型[temp.deduct.type]中推导出模板参数

8 A template type argument T , a template template argument TT or a template non-type argument i can be deduced if P and A have one of the following forms: 8如果PA具有以下形式之一,则可以推导出模板类型参数T ,模板模板参数TT或模板非类型参数i

[...] [...]

T&
T&&

[...] [...]

It's not exactly clear, but this requires P (the parameter) and A (the argument) to both have the same form. 它并不完全清楚,但这需要P (参数)和A (参数)都具有相同的形式。 They need to both be of the T& form, or both of the T&& form. 他们既需要T&形式,也需要T&&形式。 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: 例外情况, T &&可以从U &推导出来的情况是通过在匹配发生之前将T &&更改为plain T来完成的,在有限的情况下:

10 Similarly, if P has a form that contains (T) , then each parameter type P i of the respective parameter-type-list of P is compared with the corresponding parameter type A i of the corresponding parameter-type-list of A . 10类似地,如果P具有包含形式(T)然后每个参数类型P i的相应的参数类型列表P与对应的参数进行比较型A i的相应的参数类型列表A If P and A 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) and P i and A i are parameters of the top-level parameter-type-list of P and A , respectively, P i is adjusted if it is an rvalue reference to a cv-unqualified template parameter and A i is an lvalue reference, in which case the type of P i is changed to be the template parameter type (ie, T&& is changed to simply T ). 如果PA是在获取函数模板的地址(14.8.2.2)或从函数声明(14.8.2.6)中推导出模板参数时起源于演绎的函数类型,并且P iA i是顶部的参数 - PA级别参数类型列表 ,如果它是对cv非限定模板参数的右值引用并且A i是左值参考,则调整P i ,在这种情况下, P i的类型被改变为模板参数类型(即T&&更改为T )。 [...] [...]

and

14.8.2.1 Deducing template arguments from a function call [temp.deduct.call] 14.8.2.1从函数调用中减去模板参数[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 to A " is used in place of A for type deduction. 3 [...]如果P是对cv-nonqualified模板参数的rvalue引用,并且参数是左值,则使用类型“对A左值引用”代替A进行类型推导。 [...] [...]

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. invalid: const T不能从void()推导出来,即使T = void()会给出完全相同的结果,并且调用f<void()>也会成功。

Wintermute's deleted answer showed that you can use Wintermute删除的答案显示你可以使用

 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 . 相反:这允许将Types推导为左值引用,rvalue引用或非引用,具体取决于value的类型。

Did you intend to use && in std::tuple<Types&&...> as a universal reference? 您是否打算在std::tuple<Types&&...>使用&&作为通用引用? This is not universal reference; 这不是普遍的参考; it is rvalue reference and can only bind to rvalues. 它是rvalue引用,只能绑定到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. 你可以看到,即使对于int类型,它也推导为rvalue引用。 Rvalue references cannot bind to lvalues. Rvalue引用不能绑定到左值。 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] . 因此,推导出const char(&&)[5]是正确的,并且字符串文字不能转换为const char(&&)[5] If you call print_tuple like: 如果你调用print_tuple

print_tuple(std::forward_as_tuple(string("test"),1));

It will work. 它会工作。 Now the type is tuple<string&&, int&&> . 现在类型是tuple<string&&, int&&>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM