c++ - 根据参数的值类别调用函数

标签 c++ c++11

昨天我问了a question about when to use std::forward and when to use 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':对重载函数的模糊调用

我在这里错过了什么?为什么最后一次调用 foo(a, b) 没有调用 void exp(T& a, T& b) 函数?

最佳答案

引用绑定(bind)和左值到右值的转换都被赋予了完全匹配等级:

§ 13.3.3.1.4 [over.ics.ref]/p1:

When a parameter of reference type binds directly (8.5.3) to an argument expression, the implicit conversion sequence is the identity conversion.

因此,编译器无法在更好的转换顺序选择的基础上在两者之间进行选择,而试图对exp的两个重载进行部分排序(因为更专业的函数模板优先过载决议)。然而:

§ 14.8.2.4 [temp.deduct.partial]/p5:

Before the partial ordering is done, certain transformations are performed on the types used for partial ordering:

— If P is a reference type, P is replaced by the type referred to.

— If A is a reference type, A is replaced by the type referred to.

这使得这两个重载无法区分,因为它们都不是更特殊的,因为从部分排序的角度来看它们看起来是一样的,并且没有其他异常(exception)适用。

如果您的主要目标是对右值进行一次重载,对左值进行一次重载,您可以按如下方式定义它们:

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.deduct.partial]/p9:

If, for a given type, deduction succeeds in both directions (i.e., the types are identical after the transformations above) and both P and A were reference types (before being replaced with the type referred to above):

— if the type from the argument template was an lvalue reference and the type from the parameter template was not, the argument type is considered to be more specialized than the other; otherwise [...]

这使得 exp(T& a, T& b) 成为左值的首选,而 exp(T&& a, T&& b) 是唯一可行的右值转。

DEMO

关于c++ - 根据参数的值类别调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32368890/

相关文章:

c++ - 静态方法可以访问同一类的私有(private)方法吗?

c++ - 标准 : container c++ move to front

c++ - 如何从用花括号初始化的对象中捕获异常抛出?

c++ - 将 vector 传递给可变参数模板

c++ - 在这种情况下我应该使用智能指针吗?

c++ - 链接 SFML 时出错。 LNK2001

c++ - 如何使用 TagLib 读取/写入不同音频格式的封面?

c++ - 使用或不使用 C++0x 特性

c++ - 迭代对象 vector 并找到与从文本文件中提取的变量相匹配的变量

c++ - 将 std 绑定(bind)传递到函数映射的问题