无法用比较器初始化std :: function

For*_*bit 8 c++ c++11

在我的C++类中,我们学习使用函数对象等,但现在我们得到了一个代码片段,可以在教师编译器上运行,但不在我们的编译器上(我们使用不同的操作系统).

我们使用几个编译器(MSVC,clang)测试了下面的代码片段,他们都拒绝了它,有点最小化:

#include <functional>

struct Fraction {
  Fraction();
  Fraction(int z, int n);
  Fraction(Fraction&);

  // various data members
};

struct FractionComparator {
  int operator()(Fraction a, Fraction b) {
    return 1;
  }
};

int main() {
  std::function<int(Fraction, Fraction)> comparator = FractionComparator();
}
Run Code Online (Sandbox Code Playgroud)

我们对macOS表示赞同:

No viable conversion from 'FractionComparator' to 'function<int (Fraction, Fraction)>'
Run Code Online (Sandbox Code Playgroud)

我们已经发现添加移动构造函数可以解决问题,但是我们不知道为什么存在这种差异以及为什么这些代码不能在我们的编译器上编译.

有任何想法吗?

AMA*_*AMA 13

为什么添加移动构造函数可以解决问题?

Fraction试图从右值复制构造.

但是constuctor Fraction(Fraction&);采用非常量引用.不允许非const引用绑定到临时对象.正确的构造函数签名应该是:

Fraction(const Fraction&);
Run Code Online (Sandbox Code Playgroud)

当您声明移动构造函数时,编译器将从Fractionrvalue 移动构造.

为什么这段代码不能在我们的编译器上编译,而是编译给老师?

此代码使用VC++编译.看起来编译器不符合此处的标准.我可以更详细地找到这个StackOverflow问题.它似乎是一个编译器扩展,允许它编译.如果通过/Za标志禁用编译器扩展,则它将不再编译.

  • [错误再现](https://wandbox.org/permlink/QYC5AWVrpod3hM4c),[修复证明](https://wandbox.org/permlink/E0GiICZOgUEK01cP). (3认同)

AnT*_*AnT 7

从C++ 14开始,你要使用不参与重载解析,除非目标函数的构造是可调用与给定的参数(与std::declval<>()给定类型的参数).在你的情况下,这将是std::declval<Fraction>()争论.

你的FractionComparator仿函数不能用std::declval<Fraction>()参数调用,因为它通过值接收它的参数,而类型的临时对象Fraction不能被复制:Fraction'copy-constructor的参数被声明为非const引用.

将复制构造函数声明为

Fraction(const Fraction &);
Run Code Online (Sandbox Code Playgroud)

并且代码将编译.如果你有充分的理由将它保持为非常数,那么你将不得不探索其他机会来完成这项工作.为什么你FractionComparator坚持按价值接收参数呢?

您的问题标记为C++ 11,但显然您的编译器即使在C++ 11模式下也会追溯性地实现此C++ 14要求.