隐式模板推导指南可以推导出引用类型吗?

Oli*_*liv 4 c++ templates c++17

在使用gcc7测试C++ 17演绎指导行为时,我发现此示例失败:

template<class T>
struct S{
  S(T&& v){}
};
int i=10;
auto v = S(i);
Run Code Online (Sandbox Code Playgroud)

根据我从cpp引用中读到的内容,我认为v应该是类型S<int &>.然而gcc7没有编译这段代码抱怨a int&不能绑定到a int &&(通用引用机制失败).

所以我的问题是:

  1. 应该gcc7推断出v类型S<int&>

  2. 工作草案标准中哪里描述了自动扣除指南?

Bar*_*rry 7

[over.match.class.deduct]中的规则是:

形成一组函数和函数模板,包括:
- 对于由模板名称指定的主类模板的每个构造函数,如果定义了模板,则具有以下属性的函数模板:
    - 模板参数是模板参数类模板后跟构造函数的模板参数(包括默认模板参数),如果有的话.
    - 函数参数的类型是构造函数的类型.
    - 返回类型是由模板名称和模板参数指定的类模板特化,对应于从类模板获得的模板参数.

我们的套装包括:

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
Run Code Online (Sandbox Code Playgroud)

我们像往常一样执行重载决策,这涉及模板推导.但是[temp.deduct.call]:

转发参考是一个rvalue参照CV-不合格模板参数不代表一类模板的模板参数(类模板参数推导过程中([over.match.class.deduct])).如果P是转发引用且参数是左值,则使用类型"对A的左值引用"代替A来进行类型推导.

因此,这T&&转发参考.它是一个右值引用T.因此,对左值(在我们的例子中S(i))的推论失败了.gcc在这里拒绝您的代码是正确的.

如果您希望类模板参数用作转发引用,则需要添加演绎指南:

template <class T> S(T&& ) -> S<T>;
Run Code Online (Sandbox Code Playgroud)

  • @JohannesSchaub-litb在推导指南中,它不是类模板的模板参数,而是推导指南的模板参数。 (2认同)