2013-10-03 4 views
6

У меня есть иерархия, которая представляет собой некоторую часть клиента HTTP и выглядит следующим образом:C++ перегрузка оператора множественного наследования от шаблонов

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") (и позже будет повторно использовать WithHeaders в соответствующем классе Response).

код, который я пытаюсь скомпилировать это:

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] 

Я должен что-то не хватает, но это, кажется, довольно легко отличить от ParamHeader во время компиляции. Таким образом, возникают следующие вопросы:

  • Почему это не удается и как его исправить?
  • - это разумная вещь вообще или есть более простой дизайн?
+0

Пожалуйста, покажите точный код, который дает вам ошибку. Кроме того, ваш параметр 'q' должен, вероятно, быть принят' const & '. И есть ли какие-либо преобразования операторов или операторов в 'Header' или' Param'? – Angew

+0

@ Ангел добавил код. 'const' не было, действительно. Нет конвертирующих ctors (они пытались выполнить «Заголовок» h = Param («a», «b») », что не удалось). – bereal

+0

Какова связь между 'HttpRequest' и' Request'? из кода кажется, что оператор << вернет ссылку на объект типа Request, в то время как кажется, что ваш объект имеет тип HttpRequest. – ajcaruana

ответ

5

Я считаю, что это должно сработать, так что это скорее всего ошибка GCC.Как указано @refp в комментариях, поиск действительно неоднозначен, и GCC правильно отклоняет его.

Это, как вы сделать его работу:

class Request: public WithQuery<Request>, public WithHeaders<Request> { 
public: 
    using WithHeaders<Request>::operator<<; 
    using WithQuery<Request>::operator<<; 
}; 

Live example

+0

Не уверен, что это ошибка GCC, * наследование * + * имя-разрешение * в стандарте может сказать, что код является незаконным (ваше исправление действительно исправляет это, хотя). –

+0

Это потрясающе, спасибо! Но что именно означает ли это и почему это имеет значение? – bereal

+1

@bereal Декларация 'using X' вводит имя' X' в область видимости.Другими словами, здесь вы явно указываете, что 'Request' имеет функции-члены' WithHeaders :: operator << 'и' WithQuery :: operator << '. Это упрощает поиск имени. – Angew

Смежные вопросы