Template specialization for an empty parameter pac

2019-03-15 07:41发布

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.

3条回答
forever°为你锁心
2楼-- · 2019-03-15 08:26

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

查看更多
混吃等死
3楼-- · 2019-03-15 08:42

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)> { };
查看更多
Root(大扎)
4楼-- · 2019-03-15 08:44

Since you can't partially specialize functions, you need to wrap your functionality:

template<int Head, int... Tail>
struct Tmax{
  static int do(){
    return Head > Tmax<Tail...>::do() ? Head : Tmax<Tail...>::do();
  }
};

template<int N>
struct Tmax<N>{
  static int do(){
    return N;
  }
};

template<int... Numbers>
int tmax(){
  return Tmax<Numbers...>::do();
}
查看更多
登录 后发表回答