8

您能否解释一下以下机制之间的区别:

int function();

template<class T>
void function2(T&);

void main() {
    function2(function()); // compiler error, instantiated as int &

    const int& v = function();
    function2(v); // okay, instantiated as const int&
}

关于实例化,我的推理是否正确?为什么不首先实例化为const T&

谢谢

4

4 回答 4

3

因为function返回一个非常量值。只有对象可以是 const,因为它们存储了一些可以在不是 const 时修改的状态。你返回的不是一个对象,而是一个纯值。从概念上讲,它们是不可修改的(例如枚举常量),但它们不是 const 限定的(同样,枚举常量)。

于 2010-06-08T06:31:35.630 回答
2

我认为您可能会对右值和 const 限定符感到困惑。 function返回 int 类型的非 const 右值临时值,因此编译器将 T 推导出为 int,因为它应该。正如您所指出的,您可以将临时绑定到 const ref (c++03 12.2/5),但编译器不会添加 cv 限定符来使函数调用格式良好。由于您无法控制模板功能,因此有两种方法(除了您发布的解决方案)。

(1) 显式模板参数:function2<const int>(function())

(2) cv 合格回报:const int function();

这两种解决方案都形成良好。(1)似乎是更好的解决方案,恕我直言,因为(2)是非常规和愚蠢的。

编辑:实际上,推导的类型可以比 ref 模板参数的参数更具 cv 限定,但前提是类型推导否则会失败(c++03 14.8.2.1/3)。在这种情况下,类型推导不会失败,但会导致格式错误的函数调用(SFINAE 不适用,因为模板函数特化本身没有格式错误)。

如果模板作者的意图是不修改参数,则应将其声明为 const 引用参数,因此这可能是模板库中的错误,或者它可能会修改参数,在这种情况下,您所做的将在函数尝试修改参数时失败。

编辑:正如 FredOverflow 指出的那样,非类右值始终是标准 3.10/9 不合格的 cv。所以(2)在 gcc 4.3 下工作,实际上是一个编译器错误(gcc <4.5,根据 FredOverflow)。

于 2010-06-08T07:09:52.657 回答
0

在这一行

function2(function()); 

在 function2 返回之后,传递给它的参数可能会改变它的值,但是由于 function() 返回并且它只是分配给一个临时变量,但是这个临时变量在超出范围后会发生什么是问题所在,那就是为什么编译器抱怨。

于 2010-06-08T05:41:22.367 回答
0

要编译第一个调用,必须使用 T&& 参数定义 function2 - 这是右值,对临时对象的引用。在第二次调用中,v 是左值引用,就可以了。如果您的编译器不支持右值引用,则第一次调用可能只使用 T 参数编译,不带引用。

于 2010-06-08T05:46:36.377 回答