【问题标题】:C++: template function with explicitly specified reference type as type parameterC++:具有显式指定引用类型作为类型参数的模板函数
【发布时间】:2014-12-02 18:34:32
【问题描述】:

我在玩 C++ 模板类型推导,并设法编译了这个小程序。

template<typename T>
 void f(const T& val)
 {
   val = 1;
 }


 int main()
 {
    int i = 0;
    f<int&>(i);
 }

它可以在所有主要编译器上编译,但我不明白为什么。为什么f 可以分配给val,而val 被明确标记为const?是这些编译器中的错误还是根据 C++ 标准的有效行为?

【问题讨论】:

  • 参考折叠。
  • @πάνταῥεῖ 这对我来说似乎不对。对左值引用的左值引用是左值引用,而不是右值引用,因此它应该扩展为void f(const int&amp;)。

标签: c++ function-templates


【解决方案1】:

§8.3.2 [dcl.ref]/p6:

如果 typedef-name (7.1.3, 14.1)* 或 decltype-specifier (7.1.6.2) 表示类型 TR 是对类型 T 的引用,尝试 创建类型“对 cv TR 的左值引用” 创建类型“左值 引用 T”,同时尝试创建类型“右值引用” to cv TR” 创建类型 TR。

这称为引用折叠,在 C++11 中引入。在 C++03 中,您的代码格式不正确,但一些编译器支持它作为扩展。

请注意,在const T &amp; 中,const 适用于 T 类型,因此当 T 为 int &amp; 时,const 将适用于引用类型本身(这是没有意义的,因为引用是无论如何都是不可变的),而不是所指的类型。这就是为什么参考折叠规范会忽略 TR 上的任何 cv 限定符。


*模板类型参数是 typedef-name,根据 §14.1 [temp.param]/p3:

一个类型参数,其标识符不跟在省略号后面 将其 identifier 定义为 typedef-name(如果用 class 或 typename) 或 template-name (如果用 template) 在模板声明的范围内。

【讨论】:

  • 我认为这是一个非常好的答案,直接且没有神秘感。 (+1)
【解决方案2】:

我想在其他帖子中附加以下来自 C++ 标准(8.3.2 参考)的引用

1... cv 限定的引用格式错误,除非通过使用 typedef-name (7.1.3, 14.1) 或 decltype-specificer (7.1.6.2),在这种情况下,将忽略 cv 限定符。

[ Example:
typedef int& A;
const A aref = 3; // ill-formed; lvalue reference to non-const initialized with rvalue

在上面来自 C++ 标准的示例中,最后一条语句将不会被编译,因为限定符 const 被忽略(根据引号),并且您不能将右值与非 const 引用绑定。

【讨论】:

  • 这似乎是相关的报价。
  • “忽略 cv-qualifier”部分嵌入到规范中以供参考折叠,并且不需要您引用的额外段落。注意“cv TR”部分。
  • @T.C.我可以反过来说,在我引用的引用中描述了相对于 cv-qualifiers 的参考折叠规范部分。因此,您引用的额外段落中不需要,因为本质上是关于作为模板参数的引用的 cv 限定符的问题。
【解决方案3】:

const T&amp; 在此示例中不会变成int&amp;:在f&lt;int&amp;&gt;(i) 中,您将T 显式设置为int&amp;。 const 仅在 T 的定义用于确定 val 的类型时才进入图片,它变为 const int&amp;(一个微妙之处是在此替换过程中引用被折叠,所以你不会结束类型中有两个&amp;)。

【讨论】:

  • 也许我误读了您的答案,但这是否解释了分配给const 的可能性?
  • 哦,不,它没有;我错过了问题的这一方面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-15
  • 1970-01-01
相关资源
最近更新 更多