简体   繁体   English

C ++ 11 auto,std :: function和对重载函数的模糊调用

[英]C++11 auto, std::function and ambiguous call to overloaded function

I'm wondering if anyone knows why the following sample doesn't compile giving an ambiguous call to overload function error. 我想知道是否有人知道为什么下面的示例没有编译给出过载函数错误的模糊调用。 If I replace the auto with a strongly typed functor signature, it then is able to properly distinguish between the two method overloads. 如果我用强类型仿函数签名替换auto,那么它就能够正确地区分两个方法重载。

I noticed the same issue doesn't occur when not using std::function as my overload arguments. 我注意到当不使用std :: function作为我的重载参数时不会发生同样的问题。 If my overloads take just a simple float and int, the compiler can properly distinguish between the two overloads even when using the auto keyword to define my input arguments. 如果我的重载只是一个简单的float和int,那么即使使用auto关键字来定义我的输入参数,编译器也可以正确区分这两个重载。 I'm compiling this in VisualStudio 2012. Could this just be an bug in the VS compiler? 我在VisualStudio 2012中编译它。这可能只是VS编译器中的一个错误吗? I don't have access to a machine with GCC or Clang on it right now, but does anyone know if this would compile there? 我现在无法访问带有GCC或Clang的机器,但有人知道这是否可以在那里编译?

Compile Error: ambiguous call to overload function 编译错误:对重载函数的模糊调用

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;
}

Compiles 编译

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;
}

Also Compiles 也编译

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 had a greedy template constructor that will attempt to construct it from anything at all you passed it 1 . std::function有一个贪婪的template构造函数,它会尝试从你传递它的任何东西构造它1 std::function is not very suitable for use in overload resolution. std::function不太适合在重载决策中使用。 It worked in one case because perfect matches are preferred to conversion, but as noted it is fragile. 它在一个案例中起作用,因为完美匹配比转换更受欢迎,但如上所述它很脆弱。

Note that lambdas and std::function objects are unrelated types. 请注意,lambdas和std::function对象是不相关的类型。 std::function knows how to wrap a lambda, but it can wrap any copyable invokable object. std::function知道如何包装lambda,但它可以包装任何可复制的invokable对象。 Lambdas are auto-created anonymously named classes that are copyable and invokable. Lambda是自动创建的匿名命名类,可以复制和调用。 std::function is a class designed to type-erase invocation. std::function是一个用于类型擦除调用的类。

Imagine if your overrides took short and long . 想象一下,如果你的覆盖很short long The auto x = 2.0 and short s = 2.0 would correspond to the auto x = lambda and std::function<blah> f = lambda cases. auto x = 2.0short s = 2.0将对应于auto x = lambdastd::function<blah> f = lambda情况。 When you pick the type explicitly you cause a type conversion, and the types you picked explicitly had no ambiguity. 当您明确选择类型时,会导致类型转换,并且您明确选择的类型没有歧义。 But when you did auto it took the real type -- and the real type was ambiguous. 但是,当你做auto它采用了真正的类型 - 真正的类型是模棱两可的。

SFINAE or tag dispatching using std::result_of would let you handle these overrides manually. 使用std::result_of进行SFINAE或标签分派可以让您手动处理这些覆盖。

In this changed a bit. 这改变了一点。 Now the constructor only tries to swallow compatible arguments. 现在构造函数只尝试吞下兼容的参数。 But a function returning int and one returning float are both compatible with each other, so it won't help your specific case. 但是返回int的函数和一个返回的float都是相互兼容的,所以它对你的具体情况没有帮助。


1 To a certain extent this is a flaw in std::function . 1在某种程度上,这是std::function一个缺陷。 Its "universal" constructor should really only participate in overload resolution when the type passed in is both copyable and std::result_of_t< X( Args... ) > can be converted to the result type of the std::function . 当传入的类型都是可复制的并且 std::result_of_t< X( Args... ) >可以转换为std::function的结果类型时,它的“通用”构造函数应该只参与重载解析。 I suspect post-concepts this will be added to the standard, as post-concepts this is really easy to both write and express (and very little conforming code will be broken by it). 我怀疑后期概念会被添加到标准中,因为后期概念很容易写入和表达(并且很少有符合规范的代码会被它破坏)。 However, in this particular case, this would not actually help, as int and float can be converted into each other, and there are no ways to say "this constructor will work, but really it isn't a preferred option". 但是,在这种特殊情况下,这实际上并没有帮助,因为intfloat可以相互转换,并且没有办法说“这个构造函数可以工作,但实际上它不是一个首选的选项”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM