Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template specialization for an empty parameter pack

I have a variadic template function which calls itself to determine the largest number in a list (constituted by the templatized arguments). I am trying to make a specialization for when the parameter pack is empty so I can just return the number at the front of the list, but I don't know how to do that. I am just becoming familiar with variadic templates and template specialization, but this is what I have so far:

#include <string>
#include <iostream>

using namespace std;

template <int N, int... N2>
int tmax() {
    return N > tmax<N2...>() ? N : tmax<N2...>();
}

template <int N>
int tmax() {
    return N;
}

int main() {
    cout << tmax<32, 43, 54, 12, 23, 34>();
}

However, this produces the following error:

test.cpp: In function ‘int tmax() [with int N = 34, int ...N2 = {}]’:
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 23, int ...N2 = {34}]’
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 12, int ...N2 = {23, 34}]’
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 54, int ...N2 = {12, 23, 34}]’
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 43, int ...N2 = {54, 12, 23, 34}]’
test.cpp:9:45:   instantiated from ‘int tmax() [with int N = 32, int ...N2 = {43, 54, 12, 23, 34}]’
test.cpp:18:39:   instantiated from here
test.cpp:9:45: error: no matching function for call to ‘tmax()’
test.cpp:9:45: error: no matching function for call to ‘tmax()’

I have also tried this, just to see if it would work (although it introduces the number 0 to the list randomly so that it can't ever return a number less than 0):

template <int N, int... N2>
int tmax() {
    return N > tmax<N2...>() ? N : tmax<N2...>();
}

template <>
int tmax<>() {
    return 0;
}

However, in addition to the errors mentioned above, I get this error:

error: template-id ‘tmax<>’ for ‘int tmax()’ does not match any template declaration

So what should I do to get this working?

I am using g++ 4.5.2 with the -std=c++0x flag.

like image 612
Seth Carnegie Avatar asked Jun 22 '11 00:06

Seth Carnegie


People also ask

What can the template parameter in C++ template definition be?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

What is the use of template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

What is Variadic template in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

What is a parameter pack in C++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.


2 Answers

I see two mistakes using clang.

  1. Put the overload taking a single int first.

  2. Make things unambiguous for lists of length 1. Recall that variadic lists can have zero size and when they do, it seems to me you have an ambiguity.

This compiles and runs correctly for me:

#include <iostream>

using namespace std;

template <int N>
int tmax() {
    return N;
}

template <int N, int N1, int... N2>
int tmax() {
    return N > tmax<N1, N2...>() ? N : tmax<N1, N2...>();
}

int main() {
    cout << tmax<32, 43, 54, 12, 23, 34>();
}

54

like image 57
Howard Hinnant Avatar answered Sep 26 '22 20:09

Howard Hinnant


Personally, I'd prefer using static class members over functions for this sort of thing:

template <int... N> struct max;
template <int N, int... M> struct max<N, M...> {
  static const int value = max<N, max<M...>::value>::value;
};    
template <int N, int M> struct max<N, M> {
  static const int value = N > M ? N : M;
};

int main()
{
  return max<1,2,3>::value;
}

Update: Using ildjarn's suggestion, here's the less verbose version:

#include <type_traits>
template <int... N> struct max;
template <int N, int... M> struct max<N, M...>
  : std::integral_constant<int, max<N, max<M...>::value>::value> { };
template <int N, int M> struct max<N, M>
  : std::integral_constant<int, (N > M ? N : M)> { };
like image 28
Kerrek SB Avatar answered Sep 26 '22 20:09

Kerrek SB