在使用gcc7测试C ++ 17演绎指南行为时,我发现此示例失败:
template<class T>
struct S{
S(T&& v){}
};
int i=10;
auto v = S(i);
根据我从cpp reference读到的内容,我认为v
应该是S<int &>
类型。然而,gcc7没有编译此代码,抱怨int&
无法绑定到int &&
(通用引用机制失败)。
所以我的问题是:
gcc7是否应该将v
推断为S<int&>
类型?
工作草案标准中的自动扣除指南在哪里?
答案 0 :(得分:7)
[over.match.class.deduct]中的规则是:
形成一组功能和功能模板,包括:
- 对于template-name指定的主类模板的每个构造函数,如果定义了模板,则具有以下属性的函数模板:
- 模板参数是类模板的模板参数,后跟构造函数的模板参数(包括默认模板参数),如果有的话。
- 函数参数的类型是构造函数的类型 - 返回类型是由模板名称和模板参数指定的类模板特化,对应于从类模板获取的模板参数。
我们的套装包括:
template <class T> // <-- the template parameters come from the class template
S<T> // <-- the return type is the class template specialization
foo(T&& ); // <-- the types of the parameters are those of the constructor
我们像往常一样执行重载决策,其中涉及模板推理。来自[temp.deduct.call]的但:
转发参考是对cv非合格模板参数的右值引用,它不代表类模板的模板参数(在类模板参数推断期间[( over.match.class.deduct]))。如果P是转发引用且参数是左值,则使用类型“左值引用A”代替A来进行类型推导。
因此,此T&&
不转发引用。它是T
的右值引用。因此,对左值(在我们的例子中,S(i)
)的推断失败。 gcc在这里拒绝您的代码是正确的。
如果您希望类模板参数用作转发引用,则需要添加演绎指南:
template <class T> S(T&& ) -> S<T>;