c++ 11 auto, std::function和对重载函数的二义调用
C++11 auto, std::function and ambiguous call to overloaded function
我想知道是否有人知道为什么下面的示例不编译给出一个模棱两可的调用重载函数错误。如果我用强类型函子签名替换auto,它就能正确区分这两种方法重载。
我注意到当不使用std::function作为我的重载参数时不会发生同样的问题。如果我的重载只接受一个简单的float和int,即使使用auto关键字定义输入参数,编译器也可以正确地区分这两种重载。我在VisualStudio 2012中编译这个。这可能只是一个bug在VS编译器?我现在无法访问装有GCC或Clang的机器,但是有人知道这是否可以在那里编译吗?
编译错误:调用重载函数有歧义
class AmbiguousOverload
{
public:
static void OverloadedMethod(std::function<int()>) {}
static void OverloadedMethod(std::function<float()>) {}
};
int _tmain(int argc, _TCHAR* argv[])
{
auto func1 = []() -> float {
return 0.5f;
};
auto func2 = []() -> int {
return 12;
};
AmbiguousOverload::OverloadedMethod(func1);
AmbiguousOverload::OverloadedMethod(func2);
return 0;
}
class AmbiguousOverload
{
public:
static void OverloadedMethod(std::function<int()>) {}
static void OverloadedMethod(std::function<float()>) {}
};
int _tmain(int argc, _TCHAR* argv[])
{
std::function<float()> func1 = []() -> float {
return 0.5f;
};
std::function<int()> func2 = []() -> int {
return 12;
};
AmbiguousOverload::OverloadedMethod(func1);
AmbiguousOverload::OverloadedMethod(func2);
return 0;
}
也编制
class AmbiguousOverload
{
public:
static void OverloadedMethod(int) {}
static void OverloadedMethod(float) {}
};
int _tmain(int argc, _TCHAR* argv[])
{
auto v1 = 0.5f;
auto v2 = 12;
AmbiguousOverload::OverloadedMethod(v1);
AmbiguousOverload::OverloadedMethod(v2);
return 0;
}
std::function
有一个贪婪的template
构造函数,它将尝试从你传递给它的任何东西构造它1。std::function
不太适合用于过载分辨率。它在一种情况下是有效的,因为完美匹配比转换更受欢迎,但正如前面提到的,它是脆弱的。
注意lambda和std::function
对象是不相关的类型。std::function
知道如何包装lambda,但它可以包装任何可复制的可调用对象。lambda是自动创建的匿名类,可复制和可调用。std::function
是一个用于类型擦除调用的类。
想象一下,如果您的覆盖使用short
和long
。auto x = 2.0
和short s = 2.0
对应auto x = lambda
和std::function<blah> f = lambda
。当您显式地选择类型时,会导致类型转换,并且您显式地选择的类型没有歧义。但是当你做auto
的时候,它取的是真实的类型——而真实的类型是有歧义的。
SFINAE或使用std::result_of
的标签调度将允许您手动处理这些覆盖。
在c++14中有所改变。现在构造函数只尝试吞下与兼容的参数。但是一个返回int
的函数和一个返回float
的函数都是相互兼容的,所以它对你的具体情况没有帮助。
1在一定程度上这是std::function
的一个缺陷。它的"通用"构造函数实际上应该只在传入的类型和 std::result_of_t< X( Args... ) >
都可以转换为std::function
的结果类型时才参与重载解析。我怀疑后概念将被添加到标准中,因为后概念非常容易编写和表达(并且很少有符合标准的代码会被它破坏)。然而,在这种特殊情况下,这实际上没有帮助,因为int
和float
可以相互转换,并且没有办法说"这个构造函数将工作,但实际上它不是首选选项"。
- 为什么使用SFINAE而不是函数重载
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- c++:可变模板和函数重载
- 在缺少函数重载时抛出异常,并带有 std::variant 而不是编译时错误
- 解决模板成员函数重载
- 为什么不允许成员函数和非成员函数之间的函数重载?
- 推断模板化函数中的函数重载
- C++复制函数重载导致"must be a nonstatic member function"错误
- 为什么 std::sort 找不到合适的(静态成员)函数重载?
- 可变参数泛型 lambda 和函数重载
- C++中的函数重载和继承
- 当有右值构造函数可用时,为什么从右值调用类引用构造函数重载?
- C/C++ 可变参数宏函数重载
- 将基类的成员函数重载到其他派生类C++
- C++ 函数重载匹配
- C++函数重载,具体步骤是什么
- C++:使用 param pack 显式调用函数重载
- 隐式生成的函数重载用于右值参数?
- 使用函数重载输入运算符
- 运算符重载函数上的函数重载