【问题标题】:Variadic template inheritence, member function overloading可变模板继承、成员函数重载
【发布时间】:2014-11-11 09:03:09
【问题描述】:

我正在尝试使用可变参数模板重写模板类 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;
}

我该如何解决这个问题?

【问题讨论】:

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


    【解决方案1】:

    我还没有测试过这个,但它应该是这样的:

    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()。再多做一些工作,可能也有办法解决这个问题。

    【讨论】:

      【解决方案2】:

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

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

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

      您还需要在“根”特化中声明来支持这一点:

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

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

      【讨论】:

        【解决方案3】:

        Child 继承Parent&lt;std::string, int&gt;,它是从template &lt;class... Elements&gt; 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&lt;int&gt;grandparent 类,当然有void incomingMessage(int),但是Parent&lt;std::string&gt;, int&gt;parent 类,有void incomingMessage(std::string),它隐藏了@987654329 @。

        那该怎么办? - 只需通过“使用”它来取消隐藏超类的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_);
        };
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-03-13
          • 1970-01-01
          • 2023-01-15
          • 1970-01-01
          • 2020-08-12
          • 2010-10-03
          • 2016-12-03
          相关资源
          最近更新 更多