基于参数的值类别调用函数
Calling function based on the value categories of its arguments
昨天我问了一个关于何时使用std::forward
和何时使用std::move
的问题
今天我试着应用我认为我学到的东西。我写了以下内容:
template <typename T>
void exp(T a, T b)
{
cout << "rvalues" << endl;
}
template <typename T>
void exp(T& a, T& b)
{
cout << "lvalues" << endl;
}
template <typename T>
void foo(T&& a, T&& b)
{
exp(forward<T>(a), forward<T>(b));
}
当我在main
中调用foo(4, 5)
时,它打印出"rvalue"
,正如我所期望的那样,但是当我做类似
int a = 0, b = 0;
foo(a, b);
'exp' : ambiguous call to overloaded function
我在这里错过了什么?为什么最后一次调用foo(a, b)
不调用void exp(T& a, T& b)
函数?
引用绑定和左值到右值转换都被赋予一个精确匹配的秩:
§13.3.3.1.4 [over.ics.ref]/p1:
当引用类型的形参(8.5.3)直接绑定到实参表达式时,隐式转换序列为单位转换。
因此,编译器不能根据更好的转换序列选择在两者之间进行选择,并尝试对exp
的两次重载进行部分排序(因为更专门化的函数模板在重载解析中优先)。然而:
§14.8.2.4 [temp. deduction .partial]/p5:
在完成部分排序之前,对用于部分排序的类型执行某些转换:
—如果
P
是引用类型,则将P
替换为所引用的类型。—如果
A
是引用类型,则将A
替换为所引用的类型。
这使得两个重载无法区分,因为它们都不是更专门化的,因为从部分排序的角度来看,它们看起来是一样的,并且不适用其他异常。
如果你的主要目标是一个重载左值,另一个重载右值,你可以这样定义它们:
template <typename T>
void exp(T&& a, T&& b) {}
template <typename T>
void exp(T& a, T& b) {}
现在,尽管exp(T&& a, T&& b)
对于左值也是可行的,但是另一个重载被认为是更专门化的:
§14.8.2.4 [temp. deduction .partial]/p9:
如果,对于给定类型,两个方向的演绎都成功(即,在上述转换之后类型是相同的)并且
P
和A
都是引用类型(在被上述类型替换之前):——如果实参模板的类型是左值引用,而形参的类型是左值引用模板不是,则参数类型被认为比另一个更专门化;否则[…]
这使得exp(T& a, T& b)
成为左值的首选,而exp(T&& a, T&& b)
则是右值的唯一可行。
你的exp版本打印右值不正确。应该是:
template <typename T>
void exp(T&& a, T&& b)
{
cout << "rvalues" << endl;
}
如果你调用foo(a, b),编译器可能会选择复制a和b并调用你的右值版本,而实际上它们不是右值。这就是你收到编译错误的原因。
如果你真的想知道参数是否是右值,你可以使用is_rvalue_reference:
template <typename T>
void exp(T&& a, T&& b)
{
std::cout << "rvalues: " << std::is_rvalue_reference<T&&>::value << std::endl;
}
如果你想要一个右值函数和一个左值函数,那么你可以使用enable_if:
template <typename T>
typename std::enable_if<std::is_rvalue_reference<T&&>::value, void>::type exp(T&& a, T&& b)
{
std::cout << "rvalues" << std::endl;
}
template <typename T>
typename std::enable_if<!std::is_rvalue_reference<T&>::value, void>::type exp(T& a, T& b)
{
std::cout << "lvalues" << std::endl;
}
你可能需要包括type_traits头文件
- 如何用参数值调用函数(仅在运行时已知)
- 从python中调用C++函数并获取返回值
- 当使用通配符和null指针调用函数时,对输出的说明
- 从R调用C++函数并对其进行集成时出错
- 使用QTreeView,如何通过调用函数只突出显示特定的行/列
- 如何在qt中从另一个类调用函数
- 在 COUT 语句中使用 COUT 调用函数
- 如何从线程中的不同模块调用函数?
- C++从函数指针数组调用函数
- 当 A 在 for 循环中调用函数 B 时,如何计算函数 A 的空间复杂度?
- 如何在 C/C++ 中从外部库调用函数
- 如何使用运算符在同一行中多次调用函数
- 是否可以创建一个从不同类调用函数的线程?
- 无法为类成员调用函数
- 如何从另一个标头 c++ 调用函数
- C++有什么方法可以在既不调用函数模板也不提供其模板参数的情况下引用函数模板?
- 如何只允许在调用函数 B 后调用函数 A?
- 我可以这样调用函数吗?
- 如何在 c++ 的类中递归调用函数方法?
- 为什么在指向对象的迭代器上调用函数不允许我更改对象本身?