2015-06-29 97 views
5

我正在努力理解将参考函数作为通用参考传递给函数时会发生什么(正在推导哪种类型)。让我们假设我们有一个函数foo接受一个PARAM作为通用参考:将参考函数作为通用参考传递

template<typename T> 
void foo(T&& param) 
{ 
    std::cout << __PRETTY_FUNCTION__ << std::endl; 
} 

然后让我们做到以下几点:

void(&f)(int) = someFunction; 
foo(f); 

结果将是:

void foo(T&&) [with T = void (&)int]

这是完全可以理解的:我们将lvalue传递给函数foo,所以推导的类型是void(&)int,并且参数的类型将为“void(& & &)int”,其参考折叠规则变为无效(&)int。参数将只是一个函数的左值引用。

但是,当我做到以下几点:

void(&f)(int) = someFunction; 
foo(std::move(f)); 

foo将打印:

void foo(T&&) [with T = void (&)int]

这也正是像以前一样!这里发生了什么?为什么结果与传递左值相同?我期望,因为我们传递右值到foo,所推导的类型应该是T = void(int),并且参数应该变为void(int323)。对于所有其他“常规”类型(如类,基本类型等),这总是会发生。为什么在处理函数引用时它有所不同?

+0

Nah。 'param'有一个名字,根据定义它是一个左值。 –

+3

@KerrekSB抱歉,这是错误的 - http:// stackoverflow。com/questions/7016777/what-is-rvalue-reference-to-function-type –

+0

@rubix_addict:我的不好,谢谢!删除。我是在声明之后,这是答案的一部分,但我没有把它说清楚。 –

回答

6

A std::move是一个光荣的static_cast右值引用类型。该标准表示,对函数类型的右值引用依然会产生左值。每[expr.static.cast]/P1:

表达static_cast<T>(v)的结果是将所述表达v键入T的结果。 如果T是一个左值引用类型或对函数类型的右值引用,则结果为左值;

关于std::move()函数调用,该函数返回一个右值参考指定转换的结果的值的类别,我们也可以从[expr.call]/P10看到的函数调用是一个左值如果返回类型是一个rvalue参考函数类型:

函数调用是一个左值如果结果类型是左值引用类型或一个rvalue参考函数类型,一个x值如果结果的类型是对象类型的右值引用,以及其他值rwise。

+0

非常好的答案。直观的意义是,对函数类型的引用会被区别对待;函数没有状态,因此不能移动,并且对函数的引用永远不会改变函数。有效引用函数类型总是表现为const&。虽然它仍然让我想知道为什么有必要明确说明这些转换发生。在没有这个规则的情况下,可以编造出什么奇怪的,无意义的代码示例? –

+0

啊,真好!当有多种方式来获得什么是函数xvalue时,看起来有点复杂,对于每种方式来说,它实际上都会产生一个函数左值,但实际上却是这样。 :) – hvd