我被告知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;
}
但如果不是那样,那么它匹配的区别是什么?
答案 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...)
。
除了这个左值/右值差异外,这两个函数没有其他区别。