C++ 中的链式构建器模式

Chained builder pattern in C++

我正尝试在 C++ 中创建一个链式构建器,如下所示:

#include <string>
#include <vector>

using std::string;
using std::vector;

class AbstractBuilder {
 protected:
    AbstractBuilder&
    add_field(string name, string value) {
        // blabla, add field to json structure
        return *this;
    }

};

class Event {
 public:
  class Builder : public AbstractBuilder {
   public:
    Builder& event(string event) {
      return add_field("event", event);
    }
    Builder& payload(string payload) {
      return add_field("payload", payload);
    }
  };
};

Event::Builder builder = Event::Builder().event("test");

我得到的错误是:

gcc test.cpp
test.cpp:22:14: error: non-const lvalue reference to type 'Event::Builder' cannot bind to a value of unrelated type 'AbstractBuilder'
      return add_field("event", event);
             ^~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:25:14: error: non-const lvalue reference to type 'Event::Builder' cannot bind to a value of unrelated type 'AbstractBuilder'
      return add_field("payload", payload);
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 errors generated.

我是一个C++菜鸟,不太明白这个问题以及如何解决它。 AFAIU 从 Event::Builder 中的 add_field 返回的对象将是对自身的引用,类型为 Event::Builder,而不是抽象 temp/rvalue。我错过了什么?什么可能是实现此目标的更好方法(为某些 json 结构构建一组强类型构建器)。欢迎使用任何现有示例。

谢谢

AFAIU the object returned from the add_field in the Event::Builder is going to be [...]

您正在应用更高层次的推理。允许编译器假设什么?它看到 add_field() returns AbstractBuilder& 并且您正在尝试 return 那个(来自 event()payload())作为 Builder&.如何才能做到这一点?一般来说,它不能,因为不是每个 AbstractBuilder 都是 Builder.

如果您绝对确定 add_field 将 return *this(即使在将来对代码进行修改之后),那么您可以明确告诉编译器假定 returned 引用是 Builder.

的子对象
return static_cast<Builder&>(add_field("event", event));

但这很脆弱,因为编译器无法检测到您的假设是否(在未来)被打破。您可能想要添加运行时断言来检测损坏。不那么脆弱的是强制这些函数 return *this:

add_field("event", event);
return *this;

这有其自身的缺点,因为您的代码会自行重复。 (如果你改变了这些函数的语义return,你将有多个地方需要改变。)需要做出判断,以确定哪种方法更可取,或者整体设计是否应该是重新思考。