繁体   English   中英

将 lambda 模板化的 class 存储为另一个 class 的成员时如何推断模板参数?

[英]How to deduce the template argument when storing a lambda-templated class as a member of another class?

我有一个关于将 lambda 模板化的 object 存储为 class 成员的问题。 Invoker class 是一个模板化的 class,存储任意 lambda function。我想将Invoker的实例存储在另一个 class, Worker中。 但是,当Invoker用作 class 成员时,我不知道如何填充模板参数TCallback 它不像main function 中的第一行那样推导。如评论中所示,我试图在Worker的某处定义一个 lambda 并将其传递给Invoker类型的成员。

我尝试过的是使用 class 方法的decltype但它不能像通用 lambda 那样调用 - 它需要 class object 上下文才能运行。

非常感谢任何想法和一些解决方法。

谢谢你。

#include <iostream>

template <typename TCallback>
struct Invoker {
  explicit Invoker(TCallback&& cb) : cb(cb) {}

  TCallback cb;

  void invoke() {
    cb();
  }
};

struct Worker {
  void some_callback() {
    std::cout << "callback in worker\n";
  }

  // Not working: some_callback is a member function and can only be called with the context object
  Invoker<decltype(&Worker::some_callback)> invoker{&Worker::some_callback};

  // How to make a something like this?
//   auto lambda_in_class = [&]{some_callback()};
  // Invoker<decltype(lambda_in_class)> invoker{lambda_in_class};
};

int main() {
  Invoker invoker([]{std::cout << "invoker\n";});
  Worker worker;
  worker.invoker.invoke();
  return 0;
}

你真的需要使用 remplates 吗? 这有效:

#include <iostream>
#include <functional>

struct Invoker {
  explicit Invoker(std::function<void()> cb) : cb(cb) {}

  std::function<void()> cb;

  void invoke() {
    cb();
  }
};

struct Worker {
  void some_callback() {
    std::cout << "callback in worker\n";
  }

   // Not working: some_callback is a member function and can only be called with the context object
   Invoker invoker{std::bind(&Worker::some_callback, this)};

   // How to make a something like this?
   std::function<void()> lambda_in_class = [&]{some_callback();};
   Invoker invoker1{lambda_in_class};
};

int main() {
  Invoker invoker([]{std::cout << "invoker\n";});
  Worker worker;
  worker.invoker.invoke();
  worker.invoker1.invoke();
  return 0;
}

您也可以使用模板来完成,但是您需要 lambda 的模板推导指南(即 C++17 功能):

#include <iostream>
#include <functional>

template <typename TCallback>
struct Invoker {
  explicit Invoker(TCallback cb) : cb(cb) {}

  TCallback cb;

  void invoke() {
    cb();
  }
};

template<typename T>
Invoker(T) -> Invoker<T>;

struct Worker {
  void some_callback() {
    std::cout << "callback in worker\n";
  }

  // Not working: some_callback is a member function and can only be called with the context object
  Invoker<decltype(std::bind(&Worker::some_callback, static_cast<Worker *>(0)))> invoker{std::bind(&Worker::some_callback, this)};

  // How to make a something like this?
//   auto lambda_in_class = [&]{some_callback()};
  // Invoker<decltype(lambda_in_class)> invoker{lambda_in_class};
};

int main() {
  Invoker invoker([]{std::cout << "invoker\n";});
  Worker worker;
  worker.invoker.invoke();
  return 0;
}

Lambda inside class 将仅适用于std::function ,因为不可能对 class 成员使用auto并且您不能以任何其他方式定义其类型。

对于成员函数,为了简化其使用,您甚至可以创建特殊的构造函数和推导指南。 像这样:

  // Add constructor to Invoker definition
  template<typename T>
  Invoker(void (T::*func)(), T* obj) : cb(std::bind(func, obj)) {}

// Add template guide after Invoker definition
template<typename T>
Invoker(void (T::*func)(), T* obj) -> Invoker<decltype(std::bind(func, obj))>;


  // Now you can declare invoker in Worker like this
  decltype(Invoker(&Worker::some_callback, static_cast<Worker *>(0))) invoker{&Worker::some_callback, this};

  // Or outside, like this
  Worker worker;
  auto invoker = Invoker{&Worker::some_callback, &worker};

问题在于:

Invoker<decltype(&Worker::some_callback)> invoker{&Worker::some_callback};

就是some_callback是一个非静态成员function,你调用它的时候,其实是传递给它一个隐式的this指针。 所以当你通过成员function指针调用它时,需要一个Worker的object(在你的Invoker class中不存在。


一种解决方法是使用绑定表达式将this指针与some_callback

std::bind(&Worker::some_callback, this)

然后可以将结果类型转换为std::function<void()>并存储在Worker.invoker中:

Invoker<std::function<void()>> invoker{std::bind(&Worker::some_callback, this)};

演示


另一种解决方案是改用 static 成员 function。 通过使用 static function,您将不再需要传递this指针,您可以直接使用&Worker::some_callback初始化invoker程序:

Invoker<std::function<void()>> invoker{&Worker::some_callback};

演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM