Shelwien
Shelwien

Reputation: 2200

Passing a list of classes to a template

I want to make a pipeline, where I'd specify a few processing classes as template arguments and the template would pass data between them etc.

So I've kinda got it working with VC/IntelC, but not clang/gcc. How do I fix this code and make it portable?

Here you can see that microsoft compilers understand it: https://godbolt.org/g/0UBnTU

But with gcc/clang I'm getting "explicit specialization in non-namespace scope", or "function template partial specialization is not allowed" if I try a different approach.

#include <stdio.h>

struct proc1 { int x[1]; };
struct proc2 { int x[2]; };
struct proc3 { int x[3]; };
struct proc4 { int x[4]; };

template< int N > struct S1;
template<> struct S1<0> { typedef proc1 t; };
template<> struct S1<1> { typedef proc2 t; };
template<> struct S1<2> { typedef proc3 t; };
template<> struct S1<3> { typedef proc4 t; };

template< int _N, template<int i> class Sx > 
struct S2 {
  enum{ N=_N };

  void* tbl[N];

  template< typename TT > struct print {
    template< typename Self >
    static void x( Self* This, int ii ) {
      This->tbl[ii] = new TT;
      printf( "sizeof(Sx<%i>)=%i sizeof(Self)=%i\n", ii, int(sizeof(TT)), int(sizeof(Self)) );
    }
  };

  template< class Self, template<typename TT> class func >
  struct for_all {
    template< int ii > static void x( Self* This ) {
      func< typename Sx<ii>::t >::x(This,ii);
      x<ii+1>(This);
    }
    template<> static void x<N>( Self* This ) {}
  };

  void test( void ) {
    printf( "N=%i\n", N );
    for_all<S2,print>::x<0>(this);
  }

};

S2<4,S1> X;

int main( ) {
  X.test();
}

Upvotes: 0

Views: 68

Answers (1)

Fatih BAKIR
Fatih BAKIR

Reputation: 4715

The reason your code is invalid is because there are no function template specialization in C++, therefore the template <> static void x<N>(Self* This){} is invalid.

What you can do is overloading:

template <int I>
struct integer_constant {};

template <int I>
void foo(integer_constant<I>)
{
    std::cout << I << '\n';
    foo(integer_constant<I - 1>());
}

void foo(integer_constant<0>)
{
    std::cout << 0 << '\n';
}

int main()
{
    foo(integer_constant<5>());
}

In your case, it looks like this:

template< class Self, template<typename TT> class func >
struct for_all {
    template< int ii > static void x( Self* This, integer_constant<ii> ) {
        func< typename Sx<ii>::t >::x(This,ii);
        x(This, integer_constant<ii + 1>());
    }
    static void x( Self* This, integer_constant<N> ) {}
};

I've rolled my own integer_constant for this example since you can't have C++11, but if you can, you should use something standard like std::integral_constant

Upvotes: 1

Related Questions