Avraam Mavridis
Avraam Mavridis

Reputation: 8920

Expansion of a variadic template function causes segmentation fault

I am studying the new C++11 feature about the Variadic Templates, so I wrote a fun template function:

template <typename T>
void fun(T& a) //Base to stop the recursion
{
  std::cout << a;
};

template <typename... Types>
void fun(Types... args)
{
  fun(args...);
};

The template compiles fine but when I wrote on the main something like fun(1,10.232,1232); I got a Segmentation fault. Can anybody explain to me why this happen?

Upvotes: 3

Views: 459

Answers (1)

bstamour
bstamour

Reputation: 7766

I don't know about seg-faults, but you're never calling your base function. You need the parameter list to shrink after each call:

template <typename T>
void fun(T& a) //Base to stop the recursion
{
    std::cout << a;
};

template <typename First, typename... Types>
void fun(First arg, Types... args)
{
    fun(args...); // recursion on args... (one smaller than what was passed in).
};

Your base case binds by-reference, which is not a good idea since you're passing in temporary objects at the call-site. This is probably where your seg-fault is coming from. Either change the function to accept via a const reference, or by value.

Also note that I didn't compile the above code, so you may end up getting into an ambiguous situation when you call fun with just one parameter. To fix this, change your base case to accept no arguments:

void fun()
{
    // base case: no items.
}

template <typename First, typename... Rest>
void fun(First first, Rest... rest)
{
    // one or more items (the param pack is allowed to be emoty.)
    fun(rest...);
}

or modify the recursive overload to accept two or more arguments.

// Exactly one argument.
template <typename T>
void fun(T a)
{
    std::cout << a;
};

// Two or more arguments.
template <typename First, typename Second, typename... Rest>
void fun(First first, Second second, Rest... rest)
{
    // one or more items (the param pack is allowed to be emoty.)
    fun(second, rest...);
}

Either way, try to avoid having a case where more than one function template is a candidate for expansion, and you'll avoid lots of headaches. In other words: every overload should be mutually exclusive.

Upvotes: 6

Related Questions