c++ - 绑定(bind)到可变成员函数

标签 c++ variadic-templates crtp

情况是这样的:我有两个通过 CRTP 静态继承的类。基类有一个 run 方法,它使用可变参数模板调用派生方法,因此参数是灵活的。现在派生类包含一个函数对象。派生类具有由基类调用的实现。这似乎是不必要的,但在这段代码的完整版本中,运行的命令不仅仅是包含的函数。接下来是一个通过绑定(bind)所有可变参数将函数转换为 bool(void) 函数的方法,并将实例转换为方法 CrtpBase::Run。这是我遇到问题的地方。我尝试了两种不同的方法,使用 lambda 的版本被注释掉了。两种方法都不起作用。我的目标是让 VoidFunction 绑定(bind)所有参数,这样我就可以在没有参数的情况下随意执行函数。我在这里做错了什么?

#include <functional>
#include <utility>

template <typename D>
struct CrtpBase {
  template <typename ... Args>
  bool Run(Args&& ... args) const {
    return static_cast<D&>(*this).Impl(std::forward<Args>(args) ...);
  }
};

template <typename ... Args>
struct CrtpDerived : public CrtpBase<CrtpDerived<Args ...>> {
  CrtpDerived(std::function<bool(Args ...)> function) : runable(std::move(function)) {}

  bool Impl(Args&& ... args) const {
    return this->runable(std::forward<Args>(args) ...);
  }

  std::function<bool(Args ...)> runable;
};

template <typename D, typename ... Args>
std::function<bool()> VoidFunction(CrtpBase<D> base, Args&& ... args) {
//  return [&base, &args ...]()->bool{return CrtpBase<D>::template Run<Args ...>(base);};
  return std::bind(CrtpBase<D>::template Run<Args ...>, base, std::forward<Args>(args) ...);
}

int main(int argc, char** argv) {
  std::function<bool(int&)> fn = [](int& a)->bool{a /= 2; return (a % 2) == 1;};
  CrtpDerived<int&> derived(fn);
  int x = 7;
  auto voided = VoidFunction(derived, x);
  bool out = voided();
  if ((x == 3) and (out == true)) {
    return EXIT_SUCCESS;
  } else {
    return EXIT_FAILURE;
  }
}

编辑:

  1. 修复了最终测试中的拼写错误 (out == false) 变成了 (out == true)

最佳答案

首先,从编译器的角度来看CrtpBase<D>::template Run<Args ...>是无意义/不完整的标记组合。 C++ 中没有这样的表达式语法。这看起来像是试图形成指向成员的指针,但这需要显式应用 &运算符(operator)

return std::bind(&CrtpBase<D>::template Run<Args ...>, base, std::forward<Args> (args) ...);

其次,这个 Actor

static_cast<D&>(*this)

将尝试抛弃常量。这在 static_cast 中是不允许的.

第三,你的

std::bind(&CrtpBase<D>::template Run<Args ...>, base, std::forward<Args> (args) ...);

绑定(bind)隐含的 this函数参数的参数 base .这是行不通的,因为 base将尽快销毁 VoidFunction退出(或一旦调用表达式结束)。正如@aschepler 在通过 base 的评论中正确指出的那样作为 CrtpBase<D>值切片原始 CrtpDerived<int&>目的。通过引用传递它,然后使用 &base作为 std::bind 的参数.

第四,std::bind will not bind "by reference" , 和 std::forward不会帮助你。这意味着 a在你的 lambda 里面 fn不会绑定(bind)到 x .使用 std::ref解决该限制。

#include <functional>
#include <utility>

template <typename D>
struct CrtpBase {
  template <typename ... Args>
  bool Run(Args&& ... args) const {
    return static_cast<const D&>(*this).Impl(std::forward<Args>(args) ...);
  }
};

template <typename ... Args>
struct CrtpDerived : public CrtpBase<CrtpDerived<Args ...>> {
  CrtpDerived(std::function<bool(Args ...)> function) : runable(std::move(function)) {}

  bool Impl(Args&& ... args) const {
    return this->runable(std::forward<Args>(args) ...);
  }

  std::function<bool(Args ...)> runable;
};

template <typename D, typename ... Args>
std::function<bool()> VoidFunction(CrtpBase<D> &base, Args&& ... args) {
  return std::bind(&CrtpBase<D>::template Run<Args ...>, &base, std::forward<Args>(args) ...);
}

int main(int argc, char** argv) {
  std::function<bool(int&)> fn = [](int& a)->bool { a /= 2; return (a % 2) == 1; };
  CrtpDerived<int&> derived(fn);
  int x = 7;
  auto voided = VoidFunction(derived, std::ref(x));
  bool out = voided();
  if ((x == 3) && (out == false)) {
    return EXIT_SUCCESS;
  } else {
    return EXIT_FAILURE;
  }
}

最后一件事:我不明白你为什么期待你的 out成为false最后。

关于c++ - 绑定(bind)到可变成员函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52047893/

相关文章:

c++ - 使用模板特化拆分可变参数包

c++ - Concepts lite是否会改变CRTP实现静态多态的需求?

c++ - C++ 中两种不同的 mixin 模式。 (混合?CRTP?)

C++ 和 CRTP 模式实现和编译器困境

c++ - Google Filament渲染引擎分割错误

c++ - 源文件具有不同编译器标志的 Makefile

c++ - 在编译时生成一个零序列

c++ - 扩展容器到参数包

C++ API 设计方法

c++ - 在 friend 的类中包含头文件