c++ - 基类型为函数引用时右值引用重载

标签 c++ c++11

我有一个类似于此的类,它应该接受一个函数对象并在以后使用它:

template<typename F>
class A {
public:
  A(const F& f) : _f(f) {}
  A(F&& f) : _f(std::move(f)) {}

private:
  F _f;
};

我还定义了一个方便的初始化函数和一个虚拟测试函数:

template<typename F>
A<F> MakeA(F&& f) {
  return A<F>(std::forward<F>(f));
}

void foo() {}

我收到无法重载 A<F>::A(F&&) 的错误与 A<F>::A(const F&)对于 F = void(&)()当我打电话时:

auto a = MakeA(foo);

我知道我可以通过使用函数指针而不是函数引用来修复它,并且 lambda 也能很好地工作:

auto a1 = MakeA(&foo);
auto a2 = MakeA([]{});

函数引用有什么特别之处,为什么重载在那里不起作用?

Test code here.

最佳答案

来自 clang 的错误消息更具启发性:

6 : error: multiple overloads of 'A' instantiate to the same signature 'void (void (&&)())'

这是因为对于任何左值引用类型T = U&T&&T const&是相同的类型,根据 [dcl.ref] 中的引用折叠规则:

6 - If [...] a type TR [is] a reference to a type T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR [...]

using T = int&;
static_assert(std::is_same<T&&, T const&>::value, "!!");

真正的问题是您在其适用范围之外应用“通用引用/std::forward”模式;它仅适用于完美转发参数。如果您传递 lambda 左值,您的代码也会中断:

auto l = []{};
auto d = MakeA(l);    // breaks

编写类型推导构造函数的正确方法是将 decay 应用于参数类型(参见 make_optional ):

template<typename F>
A<typename std::decay<F>::type> MakeA(F&& f) {
  return A<typename std::decay<F>::type>(std::forward<F>(f));
}

关于c++ - 基类型为函数引用时右值引用重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24549008/

相关文章:

c++ - 如何从文件中的特定行读取 (C++)

c++ - 捕获析构函数中抛出的异常的 block

ios - 如何在 Cordova 中启用 c++11?

c++ - 如何保证移动不妨碍RVO?

c++ - Visual Studio 2015 (C++) : Stop compile on first build error (not first project)

C++尝试按平均值对类数组进行排序,然后按递增顺序对它们进行排序

c++ - 为每个参数选择调用一次的静态变量和函数

c++ - 使用 boost::filesystem 对目录的子文件夹和文件名进行数字排序

c++ - 输入流上的基于范围的循环

c++ - 从 lambda 中的容器中删除 self