C++ 在映射中存储变体类型

问题描述 投票:0回答:1

在 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 等,它就无法编译。

c++ c++17
1个回答
1
投票

显而易见的解决方案是仅使用一个函数来解析和使用字符串,并直接使用一点 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)); } },
    /* ... */
};
© www.soinside.com 2019 - 2024. All rights reserved.