您能否解释一下以下机制的区别:
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&
?
谢谢
答案 0 :(得分:3)
因为function
返回非const值。只有对象可以是const,因为它们存储了一些可以修改的状态,如果它不是const的话。你返回的不是一个对象,而是一个纯粹的价值。从概念上讲,它们不可修改(例如枚举常量),但它们不是const限定的(再次,枚举常量)。
答案 1 :(得分:2)
我认为你可能会在rvalues和const限定符之间感到困惑。 function
返回一个int类型的非const rvalue临时,因此编译器将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引用参数,所以这可能是模板库中的一个bug,或者它可能会修改参数,在这种情况下你是什么在函数尝试修改参数时,正在执行的操作将失败。
编辑:正如FredOverflow指出的那样,非类别的右值总是cv不符合标准3.10 / 9。所以(2),它在gcc 4.3下工作,实际上是一个编译器错误(gcc&lt; 4.5,根据FredOverflow)。
答案 2 :(得分:0)
在这一行
function2(function());
在function2返回之后,传递给它的参数可能会改变它的值,但是因为function()返回并且它刚刚被分配给一个临时变量,但是这个临时变量超出范围后会发生什么呢?问题,这就是编译器投诉的原因。
答案 3 :(得分:0)
要编译第一个调用,必须使用T&amp;&amp ;;定义function2。参数 - 这是rvalue,对临时对象的引用。在第二次调用中,v是左值引用,可以。如果您的编译器不支持rvalue引用,则第一次调用可能只使用T参数编译,不带引用。