在 C++ 中,我想创建定义数据管道的函数对列表。 例如,给出这样的内容:
FieldName: "F1"
ParserFunction: X ParseX(string s)
DestinationFn: void Consume(X& f1)
FieldName: "F2"
ParserFunction: Y ParseY(string s)
DestinationFn: void Consume(Y& f2)
我希望能够将此列表存储在像地图这样的数据结构中,其中给定字段名称和数据的字符串,调用正确的解析器和消费者。
到目前为止,我想出的最好的方法是这样的:
using ParseResult = std::variant< X, Y >;
map< string, pair< std::function<ParseResult(string)>, std::function<void(ParseResult)>>
这允许自然地编写解析器(并且可以重用现有的解析器):
int StringToInt(const string& s) { return 42; }
但是消费者必须使用变体:
void ConsumeInt(ParseResult i) { foo = std::get<int>(i); }
这可行,但如果参数实际上不携带整数,则可能会出现运行时错误。这也意味着对于任何给定的应用程序,Variant 类型必须声明所有可能的类型。对于可能有大量类型的长转换器列表。
有没有办法声明映射的内容,以便每行在构造上都是完全类型安全的,但行是类型变体(或类型擦除)的?
换句话说,我想要:
void TypesafeIntegerSink(int i) { ... }
我的地图初始值设定项如下所示:
mymap = {
{ "F1", { StringToInt, TypesafeIntegerSink } },
{ "F2", { StringToX, TypesafeXSink } },
....
}
我想知道是否有一种聪明的方法来构造它,以便如果 F1 解析器不返回 int,或者 F1 接收器不接受 int 等,它就无法编译。
显而易见的解决方案是仅使用一个函数来解析和使用字符串,并直接使用一点 lambda 来构建它:
std::map<std::string, std::function<void(std::string)>> mymap = {
{ "F1", [](std::string in) { TypesafeIntegerSink(StringToInt(in)); } },
{ "F2", [](std::string in) { TypesafeXSink(StringToX(in)); } },
/* ... */
};