Variadic templates expansion recursively for classes and functions
c++, c++11, metaprogramming, variadic-templates, visual-studio-2013
Solution
First of all: To allow polymorphic templates, you have defined a non-templated pure-virtual base class `Slave`. Your template class `Slave_T` must inherit from it (You want a `std::vector` containing heterogeneous templates, right?). And note that you are using the virtual function defined by the base class `Slave`. I think you have forgotten to write the base class list before `struct Slave_T` :)
Second: In that override of the virtual function `Type()`, you have written `Slave<T>::type` instead of `Slave_T<T>::type`. Also note that this sentence needs `typename` keyword before it, because is a reference to a dependent scope.. But, on the other hand, you have access to the `Slave_T` template param `T`, so, why you don't simply use `T`? :)
Third: Prefer to use `std::make_shared` instead of a raw `new` sentences.
Fourth: Prefer `std::string` instead of C-style raw-strings.
Edit after code fixes:
Template param `T` of private function `MakeSlave()` shadows the class variadic template param `T`. You must have to use other name.
By the way, the error is that in the overloads of makeslave are ambiguous: You have defined a version with template params `T` and variadic `Params`, that is, the tipicall HEAD TAIL recursive approach used with variadic packs. But, on the other hand, you also define a version with only one template param. Note that this make ambiguity with the first version, because a variadic pack can be empty, so in your base case the compiler donesn't know what version use.
Solution:
You could use a sentinel type to track when the param list is completely processed. You use this sentinel to enable/disable the base case to avoid the ambiguity:
template <typename ...T>
struct Master {
Master()
{
MakeSlave<T...,_my_centinel_type>();
cout << "All Slaves:" << endl;
for (auto const& slave : v){
cout << slave ->Type() << endl;
}
}
private:
struct _my_centinel_type {};
template<typename U, typename ...Rest>
typename std::enable_if<!std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave()
{
v.push_back( std::make_shared<Slave_T<U>>());
MakeSlave<Rest...>();
}
template<typename U>
typename std::enable_if<std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave(){
//The base case does anything
}
See it in action: http://ideone.com/FqMPXh#
Problem
So I've been trying to understand variadic templates a little bit more, My goal was to receive all types, expand them, and print them.. I was able to do it in for a function(found some examples) but I was not able to do it for a class Here I am trying to build a 'Master' to hold many 'Slaves', each Slave is supposed to have a Slave_T inherit from him and then know it's type, and print it on c'tor. But for some reason I am not able to fix the ambigious compilation error.. I was trying to avoid passing any of the type as parameters to the function.. I tried with enable_if or true/false_type convensions but was unable, anyone has any idea? This is my code:(function expansion included) Function expansion that works: ``` template<typename T, typename... Targs> void Print(T value, Targs... Fargs) // recursive variadic function { Print<T>(); Print(Fargs...); // recursive call } template<typename T> void Print(T = NULL) { std::cout << typeid(T).name() << endl; } ``` Class Expansion that I need help with: ``` #include <iostream> #include <vector> #include <type_traits> #include <memory> using namespace std; struct Slave { virtual char const* Type() = 0; }; template<typename T> struct Slave_T : public Slave{ virtual char const* Type() { return typeid(T).name(); } }; template <typename ...T> struct Master { Master() { MakeSlave<T...>(); cout << "All Slaves:" << endl; for (auto const& slave : v){ cout << slave ->Type() << endl; } } private: template<typename T, typename ...Rest> void MakeSlave() { MakeSlave<Rest...>(); MakeSlave<T>(); } template<typename T> void MakeSlave() { v.push_back(new Slave_T<T>()); } vector<shared_ptr<Slave>> v; }; int main() { Master<int, double, char> m; //Print("Hello", '!', 123, 123); return 0; } ``` Thanks! Alon