Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

recursive variadic template to print out the contents of a parameter pack

How is it possible to create a recursive variadic template to print out the contents of a paramater pack? I am trying with this, but it fails to compile:

template <typename First, typename ...Args> std::string type_name () {     return std::string(typeid(First).name()) + " " + type_name<Args...>(); } std::string type_name () {     return ""; } 

How shall I end the recursion?

like image 568
Gabor Marton Avatar asked Aug 19 '11 17:08

Gabor Marton


People also ask

How to iterate the pack parameters of a variadic template?

At the end of compile-time, a variadic template function is translated into multiple solid functions that each of them accepts a certain number of parameters with certain types. There is no explicit for-loop commands to iterate the pack parameters. Parameters were separated with recursive functions.

What is a variadic template?

This means that all functions that have 1 or more arguments are matched to the variadic template and all functions that with no argument are matched to the empty function. This article is contributed by MAZHAR IMAM KHAN.

What are C++ Variadic templates and fold expressions?

What are C++ variadic templates and fold expressions? Introduced in C++11, a variadic template is a function or class template that accepts a parameter pack. The pack can have arbitarary number of parameters having different types.

How to know how many arguments are actually passed in variadic templates?

When using variadic templates you may end up in a situation, where you would like to know how many arguments are actually passed. Let’s say that you want to store them in a table. How big should it be? sizeof... () will tell you: template <typename... Args> void func (Args... args) { int argsTable [sizeof... (args)] = {args...};


2 Answers

There's actually a very elegant way to end the recursion:

template <typename Last> std::string type_name () {     return std::string(typeid(Last).name()); }  template <typename First, typename Second, typename ...Rest> std::string type_name () {     return std::string(typeid(First).name()) + " " + type_name<Second, Rest...>(); } 

I initially tried template <typename Last> and template <typename First, typename ...Rest> but that was considered ambiguous (Rest can be zero elements). This question then showed me the definitive solution: Compilation Error on Recursive Variadic Template Function


Note, to avoid a bit of code duplication, you could also do:

template <typename Last> std::string type_name () {     return std::string(typeid(Last).name()); }  template <typename First, typename Second, typename ...Rest> std::string type_name () {     return type_name<First>() + " " + type_name<Second, Rest...>(); } 
like image 137
Aberrant Avatar answered Sep 24 '22 17:09

Aberrant


You need to use partial specialisation to end the recursion, but since you can't partially specialise free functions in C++, you need to create an implementation class with a static member function.

template <typename... Args> struct Impl;  template <typename First, typename... Args> struct Impl<First, Args...> {   static std::string name()   {     return std::string(typeid(First).name()) + " " + Impl<Args...>::name();   } };  template <> struct Impl<> {   static std::string name()   {     return "";   } };  template <typename... Args> std::string type_name() {     return Impl<Args...>::name(); }  int main() {   std::cout << type_name<int, bool, char, double>() << std::endl; // "i b c d"   return 0; } 

That first declaration of Impl is just a workaround for a shortcoming in g++ 4.6 (and below). It won't be necessary once it implements variadic templates correctly.

Check it out in action at ideone.com

like image 28
Peter Alexander Avatar answered Sep 20 '22 17:09

Peter Alexander