【问题标题】:Composing class of several classes in C++ at runtime在运行时在 C++ 中组合几个类的类
【发布时间】:2018-01-06 05:31:39
【问题描述】:

对于我正在开发的解析器,我正在解析事件日志。在日志中,每一行都是一个事件,这样可以很容易地逐行解析文件。记录的事件在开始时有一个字符串标识符,其构造如下:

X_Y_Z

X 总是相同的,可以被解析为一个有 8 个成员的类,因为它有 8 个参数。

Y 可以是 6 种不同的类型,它们都有不同数量的参数,可以根据 Y 的类型进行不同的解释。为这 6 种类型中的每一种创建一个类是微不足道的;因为它们只是strings、ints 和bools。

Z 可以是超过 20 种不同的东西,它们都有不同数量的参数,可以用不同的方式解释。为这 20 多种类型创建一个类也很简单;因为它们只是strings、ints 和bools。

因此,事件类可以这样定义:

template<typename Y, typename Z>
struct Event {
    DateTime timestamp;
    X base;
    Y prefix;
    Z suffix;
}

这将允许我们在编译时构造任何可能的事件组合。

问题是日志文件是在运行时解析的,我希望能够在运行时编写这些类,具体取决于我的需要。此外,我想尽可能避免强制转换。

需要注意的是,我需要在解析完成后迭代这些组合事件,作为第二遍。

实现这一目标最优雅的方法是什么?

编辑:我想到的一种解决方案是使用std::variant,并将 Y 和 Z 作为基于整数的 ID 存储在事件类中。它可以工作,但我正在寻找可能比具有 20 个参数的 std::variant 更优雅的东西。

【问题讨论】:

  • 您可以在主函数中为类动态分配内存
  • 如果您的事件是 Y1,Z1 类型而不是 Y6,Z20 类型,则取决于您需要做的不同。如果答案是 - 没什么,您可能只存储一组字段。那么,是否您需要为 120 种组合中的每一种组合使用不同的逻辑?
  • 并非所有 120 种组合,假设有大约 50 条不同的路径可供选择。
  • 与使用继承(动态多态性)相比,是否有特殊需要使其成为模板(静态多态性)?
  • 不,动态多态也是可以接受的。

标签: c++ class templates inheritance


【解决方案1】:

如果基于多态的解决方案可行,您可以使用双重调度技术来做到这一点。
它遵循一个最小的工作示例来展示它是如何工作的:

struct X { int i; int j; };

struct Visitor;

struct YBase { virtual void accept(Visitor &) =0; };
struct Y1: YBase { void accept(Visitor &) override; int i; };
struct Y2: YBase { void accept(Visitor &) override; bool b; };

struct ZBase { virtual void accept(Visitor &) = 0; };
struct Z1: ZBase { void accept(Visitor &) override; double d; };
struct Z2: ZBase { void accept(Visitor &) override; char c; };

struct Visitor {
    void visit(Y1 &y1) { y1.i = 0; }
    void visit(Y2 &y2) { y2.b = true; }
    void visit(Z1 &z1) { z1.d = .42; }
    void visit(Z2 &z2) { z2.c = 'c'; }
};

void Y1::accept(Visitor &v) { v.visit(*this); }
void Y2::accept(Visitor &v) { v.visit(*this); }
void Z1::accept(Visitor &v) { v.visit(*this); }
void Z2::accept(Visitor &v) { v.visit(*this); }

struct Event {
    X base;
    YBase *prefix;
    ZBase *suffix;
};

void visit(Event &e) {
    Visitor v;
    e.prefix->accept(v);
    e.suffix->accept(v);
}

int main() {
    Y2 y;
    Z1 z;
    Event e;
    e.prefix = &y;
    e.suffix = &z;
    visit(e);
}

由于我不知道细节的真正问题是什么,我尽力给你一个有意义的例子。我想您可以使用访问者类从已删除的 Y*/Z* 实例中提取感兴趣的参数。
无论如何,这可以作为开始设计您自己的基于双重调度的解决方案的起点。

【讨论】:

    猜你喜欢
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多