重载函数类型的值(rvalue / lvalue)

时间:2015-06-29 22:21:42

标签: c++ c++11

是否可以调用一个对函数进行右值引用的函数?例如:

#include <iostream>    

void foo(void(&f)(int))
{
    std::cout << "A" << std::endl;
}

void foo(void(&&f)(int))
{
     std::cout << "B" << std::endl;
}

我可以调用foo的重载来打印&#34; B&#34;?

1 个答案:

答案 0 :(得分:2)

这是不可能的。

当你有两个这样的候选函数时,对函数类型进行左值引用的重载是总是优先于rvalue引用过载。在所有情况下,函数都被认为是左值,因此转换为左值引用是最强的。这是一些标准措辞([over.ics.rank] /p3.2.4):

  

标准转换序列S1是比标准转换序列S2更好的转换序列,如果

     
      
  • S1和S2是引用绑定(8.5.3),S1将左值引用绑定到函数左值,S2将右值引用绑定到函数左值。 [例如:

    int f(void(&)()); // #1
    int f(void(&&)()); // #2
    void g();
    int i1 = f(g); // calls #1
    
  •   
     

- 结束示例]

此处提供的评论中的代码调用gcc中的重载#2并被clang拒绝。

void foo(void(&)(int)); // #1
void foo(void(&&)(int)); // #2

void f(int);
struct wrap {
    using T = void(&&)(int);
    operator T() { return f; }
};

int main() {
    foo(wrap{}); // Calls #2 in gcc, error in clang
}

Clang错误是:

  

对类型void (int)的非常量左值引用无法绑定到wrap类型的临时值

由于以上引用,GCC显然是错误的,但Clang也是错误的。运算符函数的结果是左值,因此它应该绑定到左值超载,但似乎clang没有尝试转换。一个更简单的例子是:

void (&r)(int) = wrap{}; // OK in gcc, error in clang

所以这看起来像是Clang和GCC中的一个错误。