使用std :: function时,选择自动返回类型的调用操作符而不是构造函数

时间:2017-09-19 08:01:16

标签: c++ c++14 std-function function-object return-type-deduction

以下代码段:

#include <functional>

struct X {
    X(std::function<double(double)> fn); // (1)
    X(double, double);                   // (2)

    template <class T>
    auto operator()(T const& t) const {  // (3)
        return t.foo();
    }
};

int main() {
    double a, b;
    auto x = X(a, b);
    return 0;
}

...使用clang时无法使用g++(4.0.1)和-std=c++14(6.3,7.2)进行编译 - 在OSX和godbolt.org上进行了测试。

但如果符合以下条件,则编译没有问题:

  • 我删除了构造函数(1);
  • 或我在double中将返回类型设置为具体类型(例如(3));
  • 或者如果我在-> decltype(t.foo())中使用尾随返回类型((3));
  • 使用-std=c++1z编译(感谢@bolov)。

也许有一些明显我在这里缺失的东西......这段代码有什么问题吗?这是一个错误吗?

1 个答案:

答案 0 :(得分:21)

您正在初始化x。由于以下原因,X是一种棘手的类型:

  1. 它可以从任何可以使用double参数调用的可调用对象构造。并且其返回类型可以转换为double。

  2. 它本身是一个可调用的对象,可以使用double参数调用。但是返回类型需要推断。

  3. 编译器为X生成了复制构造函数。

  4. 我希望这里的模糊性开始变得明显。需要重载解决。

    当您删除第一个c时,它会以明显的方式摆脱歧义。有趣的情况是函数调用操作符。

    你知道,std::function只能通过它传递的可调用构造(模板化的c只会参与重载决策)如果参数的参数之间和返回类型之间的转换是可能的。这都是在未评估的上下文中完成的,因此模板化的函数调用操作符不会被使用,因此不会被实例化。

    如果返回类型是占位符类型,则std::function c&tor;如果应该构造它,则无法轻松解析。在重载解析期间编译失败,即使成功完成,也会选择X的副本c。

    正如@VTT在评论中所建议的那样,标记接受std::function显式的c也将解决歧义。所有这些都是因为编译器根本不必对隐式转换序列进行排名。