函数类型的值性(右值/左值)重载

Overloading on valueness (rvalue/lvalue) of a function type

本文关键字:左值 重载 右值 类型 函数      更新时间:2023-10-16

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

#include <iostream>    
void foo(void(&f)(int))
{
    std::cout << "A" << std::endl;
}
void foo(void(&&f)(int))
{
     std::cout << "B" << std::endl;
}

我可以调用打印"B"的foo的过载吗?

这是不可能的。

当你有两个这样的候选函数时,对函数类型进行左值引用的重载总是优先于右值引用重载。函数在所有情况下都被认为是左值,因此对左值引用的转换是最强的。以下是一些标准措辞([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中的一个bug。