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

Mor*_*gan 5 c++ compiler-construction overloading std c++11

我想知道是否有人知道为什么下面的示例没有编译给出过载函数错误的模糊调用.如果我用强类型仿函数签名替换auto,那么它就能够正确地区分两个方法重载.

我注意到当不使用std :: function作为我的重载参数时不会发生同样的问题.如果我的重载只是一个简单的float和int,那么即使使用auto关键字来定义我的输入参数,编译器也可以正确区分这两个重载.我在VisualStudio 2012中编译它.这可能只是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;
}
Run Code Online (Sandbox Code Playgroud)

编译

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;
}
Run Code Online (Sandbox Code Playgroud)

也编译

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;
}
Run Code Online (Sandbox Code Playgroud)

Yak*_*ont 9

std::function有一个贪婪的template构造函数,它会尝试从你传递它的任何东西构造它1. std::function不太适合用于重载分辨率.它在一个案例中起作用,因为完美匹配比转换更受欢迎,但如上所述它很脆弱.

请注意,lambdas和std::function对象是不相关的类型. std::function知道如何包装lambda,但它可以包装任何可复制的可调用对象.Lambda是自动创建的匿名命名类,可以复制和调用. std::function是一个用于类型擦除调用的类.

想象一下,如果你的覆盖采取shortlong.在auto x = 2.0short s = 2.0将对应于auto x = lambdastd::function<blah> f = lambda案件.当您明确选择类型时,会导致类型转换,并且您明确选择的类型没有歧义.但是当你这样做时auto它采用了真正的类型 - 真正的类型是模棱两可的.

使用SFINAE或标签调度std::result_of可以手动处理这些覆盖.


1在某种程度上,这是一个缺陷int.当传入的类型既可复制 float可以转换为结果类型时,它的"通用"构造函数实际上只应参与重载解析std::function.我怀疑后期概念会被添加到标准中,因为后期概念很容易写入和表达(并且很少有符合规范的代码会被它破坏).但是,在这种特殊情况下,这实际上并没有帮助,因为std::result_of_t< X( Args... ) >并且std::function可以相互转换,并且没有办法说"这个构造函数可以工作,但实际上它不是一个首选的选项".