I am trying to rewrite the templated class http://docs.ros.org/hydro/api/rviz/html/c++/message__filter__display_8h_source.html to be used with multiple Message types, using variadic templates.
My first problem was how I can rewrite the example code below using variadic templates so it can be used with an arbitrary number of template arguments, not just 2.
What I need in the parent class:
processMessage for every templated typeincomingMessage for every templated typeSo if invoked for example with 2 templated types, the variadic base class should compile to something like this:
Includes:
#include<string>
#include<sstream>
#include<iostream>
using namespace std;
Working code (usual templates):
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_;
};
Not working (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_;
};
the compilation failed with:
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]
So I guess that somehow, the member function processMessage is only compiled to processMessage(std::string s) and not to the overloaded version processMessage(int a);
Example usage:
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;
}
How do I fix this issue?
I haven't tested this, but it should be somewhere along these lines:
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();
}
};
This is not perfect, you need to "propagate up" incomingMessage from the previous class, in order for it to resolve correctly in the "top level scope", so an ugly incomingMessage() in the root superclass is needed. With a bit more work, there's probably a way around that, too.
The problem is that the declaration of incomingMessage in one specialisation of Parent hides the declaration in the base class specialisation; so the only available overload in your Child class is that for string in the immediate base class.
The simplest solution is to add a using declaration to Parent to make all overloads available:
using Parent<Tail...>::incomingMessage;
You'll also need a declaration in the "root" specialisation to support this:
template<> struct Parent<>{
void incomingMessage(); // No need for a definition
};
You may also want to move messages_received_ into the "root" specialisation, so that there's a single counter for all message types rather than one for each type. If you do that, remember that it's a dependent name, so derived specialisations will have to refer to it as this->messages_received_ or Parent<>::messages_received_.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With