变量模板继承,成员函数重载

时间:2014-09-17 10:53:44

标签: c++ templates c++11 variadic-templates ros

我正在尝试使用可变参数模板重写模板化的类http://docs.ros.org/hydro/api/rviz/html/c++/message__filter__display_8h_source.html,以便与多种消息类型一起使用。

我的第一个问题是我如何使用可变参数模板重写下面的示例代码,因此它可以与任意数量的模板参数一起使用,而不仅仅是2。

我在父类中需要什么:

  • 每个模板类型的虚拟成员函数processMessage
  • 每个模板类型的每个incomingMessage的成员函数
  • 每个模板化类型的成员变量。 (稍后将成为ROS中该MessageType主题的订阅者)

因此,如果使用2个模板化类型调用,则可变参数基类应编译为如下所示:

包括:

#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_;
};

不工作(可变):

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;
}

如何解决此问题?

3 个答案:

答案 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()。通过更多的工作,也可能有一种解决方法。

答案 1 :(得分:3)

问题是incomingMessage的一个特化中Parent的声明隐藏了基类专业化中的声明;因此,Child类中唯一可用的重载是直接基类中的string

最简单的解决方案是向Parent添加一个使用声明,以使所有重载都可用:

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

您还需要在&#34; root&#34;中进行声明。专业化支持这个:

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

您可能还想将messages_received_移到&#34; root&#34;专业化,因此所有消息类型都有一个计数器,而不是每种类型的一个计数器。如果您这样做,请记住它是一个从属名称,因此派生的专精必须将其称为this->messages_received_Parent<>::messages_received_

答案 2 :(得分: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),但{em>父类Parent<std::string>, int>有{{ 1}}它隐藏了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