Shelwien Shelwien - 9 months ago 30
C++ Question

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();
}

Answer Source

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