这两个功能签名有什么区别?

时间:2015-04-19 06:46:05

标签: c++ c++11

我被告知here这两个签名之间的区别不是左值/右值。

#include <iostream>

template <typename RET_TYPE, typename...ARGs>
void takeFunction(RET_TYPE(*&& /*function*/)(ARGs...))
{
    std::cout << "RValue function" << std::endl;
}

template <typename RET_TYPE, typename...ARGs>
void takeFunction(RET_TYPE(*& /*function*/)(ARGs...))
{
    std::cout << "LValue function" << std::endl;
}

void function()
{
}

int main()
{
    void(*f)() = function;
    takeFunction(&function);
    takeFunction(f);
    return 0;
}

但如果不是那样,那么它匹配的区别是什么?

2 个答案:

答案 0 :(得分:3)

功能指向功能的指针之间存在差异。

功能不同,因为它们不是对象(在标准的标准意义上)。没有 function rvalues(在涉及非静态成员函数的某些奇怪案例之外)。实际上,无论是否命名,对函数的右值引用都是 lvalues

指向函数的指针是指针,它们是对象。您可以拥有指向函数类型的指针的prvalue,或指向函数类型的指针的xvalue,或指向函数类型的指针的左值。 &function创建一个指向函数的prvalue指针;在void (*f)() = function;中,函数到指针的转换用于将函数lvalue function转换为函数的prvalue指针,初始化f

现在考虑这组重载:

template <typename RET_TYPE, typename...ARGs>
void takeFunctionRef(RET_TYPE(&& /*function*/)(ARGs...)) // #1
{
    std::cout << "RValue function" << std::endl;
}

template <typename RET_TYPE, typename...ARGs>
void takeFunctionRef(RET_TYPE(& /*function*/)(ARGs...)) // #2
{
    std::cout << "LValue function" << std::endl;
}

takeFunctionRef(function); // calls #2
takeFunctionRef(std::move(function)); // still calls #2!

由于[over.ics.rank]中的特殊决胜局,子弹3.1.4选择了重载#2,它有利于将左值引用绑定到函数左值,而不是绑定对函数左值的右值引用。但两者都会成功绑定(即,如果删除#2,则在两种情况下都会看到#1被调用)。

答案 1 :(得分:1)

RET_TYPE(*&& /*function*/)(ARGs...)是函数指针的右值引用。

RET_TYPE(*& /*function*/)(ARGs...)是函数指针的左值引用。

&function创建一个右值临时函数指针。因此takeFunction(&function);解析为RET_TYPE(*&& /*function*/)(ARGs...)

void(*f)() = function;定义了一个命名的左值函数指针。因此takeFunction(f);解析为RET_TYPE(*& /*function*/)(ARGs...)

除了这个左值/右值差异外,这两个函数没有其他区别。