2014-09-17 3 views
2

Я пытаюсь переписать шаблонный шаблон http://docs.ros.org/hydro/api/rviz/html/c++/message__filter__display_8h_source.html, который будет использоваться с несколькими типами сообщений, используя вариативные шаблоны.Наследование шаблона Variadic, перегрузка функции-члена

Моя первая проблема была, как я могу переписать пример кода ниже, используя VARIADIC шаблонов, поэтому он может быть использован с произвольным числом аргументов шаблона, а не только 2.

Что мне нужно в родительском классе:

  • функция члена виртуальной processMessage для каждого шаблонного типа
  • функции-члена для каждого incomingMessage для каждого шаблонного типа
  • переменного для каждого члена шаблонного станда е. (Позже будет на подписчика для темы этой MessageType в ROS)

Так что, если вызывается, например, с 2-шаблонных типов, то VARIADIC базовый класс должен составить что-то вроде этого:

Включает:

#include<string> 
#include<sstream> 
#include<iostream> 
using namespace std; 

рабочий код (обычные шаблоны):

template<class MessageType1,class MessageType2> class Parent{ 
public: 

    Parent() : messages_received_(0){} 

    virtual void processMessage(MessageType1 msg) = 0; 
    virtual void processMessage(MessageType2 msg) = 0; 

    void incomingMessage(MessageType1 msg){ 
     processMessage(msg); 
     incr(); 
    } 

    void incomingMessage(MessageType2 msg){ 
     processMessage(msg); 
     incr(); 
    } 

private: 
    void incr(){ 
     cout<<"received "<<++messages_received_<<endl;; 
    } 

    MessageType1 sub1_; 
    MessageType2 sub2_; 

    int messages_received_; 
}; 

Не работает (VARIADIC):

template<class... Elements> class Parent; 
template<> class Parent<>{}; 

template<class Head, class... Tail> class Parent<Head, Tail...> : public Parent<Tail...> { 
public: 
    Parent() : messages_received_(0){} 

    virtual void processMessage(Head msg) = 0; 

    void incomingMessage(Head msg){ 
     processMessage(msg); 
     incr(); 
    } 

private: 
    void incr(){ 
     cout<<"received "<<++messages_received_<<endl;; 
    } 

    Head sub1_; 

    int messages_received_; 
}; 

компиляция завершилась с:

g++ variadic.cpp --std=c++0x 
variadic.cpp: In function ‘int main()’: 
variadic.cpp:52:33: error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive] 
/usr/include/c++/4.6/bits/basic_string.h:485:7: error: initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]’ [-fpermissive] 

Так что я думаю, что каким-то образом, функция член processMessage только компилируется processMessage(std::string s) и не перегруженной версии processMessage(int a);

Пример использования:

class Child : public Parent<std::string, int> { 
public: 
    void processMessage(std::string msg){ 
     cout<<"string: "<<msg<<endl; 
    } 

    void processMessage(int msg){ 
     cout<<"int: "<<msg<<endl; 
    } 
}; 

int main() 
{ 
     Child myMfd; 

     myMfd.incomingMessage(42); 
     myMfd.incomingMessage("abc"); 

     return 0; 
} 

Как исправить эту проблему?

ответ

4

Я не проверял, но это должно быть где-то вдоль этих линий:

template<typename ...Args> class Parent; 

template<> class Parent<> { 

public: 
    void incr(); 
    void incomingMessage() {} 
}; 

template<typename MessageType, typename ...Args> 
class Parent<MessageType, Args...> : public Parent<Args...> { 

public: 
    virtual void processMessage(MessageType msg)=0; 

    using Parent<Args...>::incomingMessage; 
    void incomingMessage(MessageType msg) 
    { 
     processMessage(msg); 
     this->incr(); 
    } 
}; 

Это не является совершенным, вы должны «распространяться вверх» incomingMessage от предыдущего класса, для того, чтобы правильно разрешить в «области верхнего уровня», поэтому требуется уродливое свойство incomingMessage() в суперклассе корня. С немного больше работы, вероятно, есть и способ обойти это.

3

Проблема заключается в том, что декларация incomingMessage по одной специализации Parent скрывает декларацию в специализации базового класса; поэтому единственная доступная перегрузка в вашем классе Child такова, что для string в базовом классе.

Самым простым решением является добавление с помощью декларации Parent сделать все перегруженные доступны:

using Parent<Tail...>::incomingMessage; 

Вам также потребуется заявление в «корневой» специализации для поддержки этого:

template<> struct Parent<>{ 
    void incomingMessage(); // No need for a definition 
}; 

Вы также можете переместить messages_received_ в «root» специализацию, так что для всех типов сообщений есть один счетчик, а не один для каждого типа. Если вы это сделаете, помните, что это зависимое имя, поэтому производные специализации должны будут ссылаться на него как this->messages_received_ или Parent<>::messages_received_.

2

Child наследует Parent<std::string, int>, который создается из template <class... Elements> class Parent. Ум, давайте посмотрим, как компилятор сможет его создать.

template<> 
class Parent<int> 
    : public Parent<> 
{ 
    // ... 
    virtual void processMessage(int msg) = 0; 

    void incomingMessage(int msg) 
    { 
     processMessage(msg); 
     incr(); 
    } 
    // ... 
}; 

template<> 
class Parent<std::string, int> 
    : public Parent<int> 
{ 
    // ... 
    virtual void processMessage(std::string msg) = 0; 

    void incomingMessage(std::string msg) 
    { 
     processMessage(msg); 
     incr(); 
    } 
    // ... 
}; 

class Child : public Parent<std::string, int> 
{ 
    // ... 

Parent<int>, то прародитель класс, имеет void incomingMessage(int) конечно, но Parent<std::string>, int>, то родительский класс, имеет void incomingMessage(std::string) и скрывает Parent<int>::incomingMessage(int).

А что делать? - просто снимите incomingMessage супер-класса, «используя» его.

template<class Head, class... Tail> 
class Parent<Head, Tail...> 
    : public Parent<Tail...> 
{ 
public: 
    using Parent<Tail...>::incomingMessage; 
    // ... 

конечно, фиктивная корень Parent должен также иметь incomingMessage.

template <> class Parent<> 
{ 
public: 
    // to forbid call dummy `incomingMessage`. 
    class dummy_ { private: dummy_() = delete; }; 
    void incomingMessage(dummy_); 
};