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,你将有多个地方需要改变。)需要做出判断,以确定哪种方法更可取,或者整体设计是否应该是重新思考。
我正尝试在 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,你将有多个地方需要改变。)需要做出判断,以确定哪种方法更可取,或者整体设计是否应该是重新思考。