【发布时间】:2019-11-30 15:28:14
【问题描述】:
我有一个玩具示例,我想在架构上进行修改以删除 Processor 对 EmitterT 的类型依赖性:
#include <iostream>
#include <utility>
using namespace std;
struct Emitter {
void e(int) { cout << "emitting int\n";}
void e(double) { cout << "emitting double\n";}
void e(char*) { cout << "emitting char*\n";}
void e(const char*) { cout << "emitting const char*\n";}
};
template <typename EmitterT>
struct Processor {
Processor(EmitterT e) : e_{e} {}
template <typename T>
void process(T&& value) {
cout << "some processing... ";
e_(std::forward<T>(value));
}
EmitterT e_;
};
template<typename Emitter_>
Processor<Emitter_> makeProcessor(Emitter_ e) { return Processor<Emitter_>(e);}
int main() {
Emitter em;
auto p = makeProcessor([&em](auto v){em.e(v);});
p.process(1);
p.process("lol");
return 0;
}
动机
我想将负责利用处理结果的部分与处理本身分离。 Emitter类结构给了我,所以我必须支持重载函数。
我想将 lambda 函数传递给将要使用它的处理器。有点像回调机制,但它必须是通用 lambda,才能支持重载。
我尝试过的:
我写的例子有效,但它依赖于Emitter 类型作为模板参数。我不喜欢根据Emitter 更改Processor 类型。它也具有传染性,我有一个真正的Processor 层次结构和Emitter 传播就像const 或更糟。
在阅读https://stackoverflow.com/a/17233649/1133179 之后,我尝试以成员身份使用以下结构:
struct EmitterC {
template<typename T>
void operator()(T value) { }
};
但是当将 Emitter 用作普通参数时,我无法想出一种方法来在 Processor 之后推迟实现 Emitter。它通过前向声明和引用EmitterC& 解决,但它只支持一个发射器定义。我能想到的唯一方法是删除 lambda,并在 EmitterC 中为我期望在 Emitter 中的每种类型进行虚拟重载,并将其用作基类。
那么,有没有办法将(通用)lambda 作为参数传递,使Processor 类型不依赖于Emitter?
我仅限于 c++14,但如果有更好的支持,我也对更现代的标准感兴趣。
【问题讨论】:
-
在您的代码中,无需将发射器存储为成员,因此您也可以简单地接受它是一个参数。
-
您可以将构造函数改为模板函数,并将其类型擦除为
std::function类成员。 -
@SamVarshavchik:
std::function的签名是什么? -
lambda 采用的参数类型及其返回值。
-
类型擦除参数到 lambda 本身。在某个时刻,某处,类型必须是已知的,或者以某种方式确定。在这一点上,真的没有什么可以说的了,太模糊了。
标签: c++ lambda c++14 generic-lambda