![](/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.