簡體   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