![](/img/trans.png)
[英]How to specify a template argument to a data member inside a templated 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.