我有一个层次结构,代表了HTTP客户端的一部分,看起来像这样:
typedef list<pair<string, string> > KeyVal;
struct Header { string name; string value; ...};
struct Param { string name; string value; ...};
/* Something that contains headers */
template<typename T> class WithHeaders {
KeyVal headers;
public:
virtual T &operator <<(const Header &h) {
headers.push_back(pair<string, string>(h.name, h.value));
return static_cast<T&> (*this);
}
};
/* Something that contains query params */
template<class T> class WithQuery {
KeyVal query_params;
public:
virtual T &operator <<(const Param &q) {
query_params.push_back(pair<string, string>(q.name, q.value));
return static_cast<T&> (*this);
}
const KeyVal &get_query() const {return query_params;}
};
/* Http Request has both headers and query parameters */
class Request: public WithQuery<Request>, public WithHeaders<Request> {...};
所以我希望能够像这样做一些事情:
request << Header(name, value) << Param("page", "1")
(并且稍后将在相应的Response
类中重用WithHeaders
)。我正在尝试编译的代码是:
Request rq = Request("unused", "unused", "unused");
rq << Header("name", "value");
然而,我得到:
test/test_client.cpp:15:30: error: request for member ‘operator<<’ is ambiguous
In file included from test/test_client.cpp:1:0:
test/../client.h:45:16: error: candidates are:
T& WithQuery<T>::operator<<(const Param&) [with T = Request]
T& WithHeaders<T>::operator<<(const Header&) [with T = Request]
我可能漏掉了些什么,但是在编译时区分Param
和Header
似乎非常容易。因此,问题是:
- 为什么会失败,如何修复?
- 这是否合理,还是有更简单的设计?
clang++
下编译通过(http://coliru.stacked-crooked.com/a/0749bab057ef385d),但在g++
下则失败了(http://coliru.stacked-crooked.com/a/5f8e26c15c188dcf)。 - Filip Roséen - refpg++
的错误消息确实令人困惑,但也许名称隐藏使代码非法(因此它不应该被编译)。 - Filip Roséen - refpg++
拒绝代码是正确的做法(尽管错误信息有误导性)。如果派生类中不存在一个 名称,但在多个基类中存在,则在进行查找时不应考虑任何一个基类。标准中可以阅读到10.2/6-7
的确切规则。 - Filip Roséen - refp