Elegant Typical Specialization

Is there an elegant way to specialize a template based on one of its template options?

Those.

template<int N> struct Junk { static int foo() { // stuff return Junk<N - 1>::foo(); } }; // compile error: template argument '(size * 5)' involves template parameter(s) template<int N> struct Junk<N*5> { static int foo() { // stuff return N; } }; template<> struct Junk<0> { static int foo() { // stuff return 0; } }; 

Those. I am trying to specialize a template based on a parameter that is divisible by 5. The only way I can do this is as follows:

 template<int N> struct JunkDivisibleBy5 { static int foo() { // stuff return N; } }; template<int N> struct Junk { static int foo() { // stuff if ((N - 1) % 5 == 0 && N != 1) return JunkDivisibleBy5<N - 1>::foo(); else return Junk<N - 1>::foo(); } }; template<> struct Junk<0> { static int foo() { // stuff return 0; } }; 

But it is much less elegant, and also requires instantiating all the templates, even if the template argument does not require it.

+4
source share
6 answers

Like this:

 #include <iostream> using namespace std; template < typename T, TN, TD > struct fraction { typedef T value_type; static const value_type num = N; static const value_type denom = D; static const bool is_div = (num % denom == 0); }; template< typename T, TN, TD, bool P > struct do_if { static void op() { cout << N << " NOT divisible by " << D << endl; } }; template< typename T, TN, TD > struct do_if< T, N, D, true > { static void op() { cout << N << " divisible by " << D << endl; } }; template < int N > void foo() { typedef fraction< int, N, 5 > f; do_if< typename f::value_type, f::num, f::denom, f::is_div >::op(); } int main() { foo< -5 >(); foo< -1 >(); foo< 0 >(); foo< 1 >(); foo< 5 >(); foo< 10000005 >(); return 0; } 
+13
source

Using the templates of the programming language D, you can write it as:

 struct Junk(int N) { static int foo() { static if (N == 0) return 0; else static if ((N % 5) == 0) return N; else return Junk!(N - 1).foo(); } } 

static if is executed at compile time.

+7
source

All calculations can be done at compile time:

 #include <iostream> template<int N> struct Junk { enum { IsDivisibleBy5 = (N % 5 == 0) }; template<bool D> struct JunkInternal { enum { Result = Junk<N-1>::Result }; }; template<> struct JunkInternal<true> { enum { Result = N }; }; enum { Result = JunkInternal<IsDivisibleBy5>::Result }; }; int main(int, char**) { std::cout << Junk< 0 >::Result << std::endl; std::cout << Junk< 7 >::Result << std::endl; std::cout << Junk< 10 >::Result << std::endl; return 0; } 
+5
source

code

 template<int A, bool = !(A % 5)> struct select : select<A-1> { }; template<int A> struct select<A, true> { static int const value = A; }; template<> struct select<0, true> { static int const value = 0; }; int main() { std::cout << select<1>::value; // 0 std::cout << select<7>::value; // 5 std::cout << select<10>::value; // 10 } 

Save the divisor variable

 template<int A, int D, bool = !(A % D)> struct select : select<A-1, D> { }; template<int A, int D> struct select<A, D, true> { static int const value = A; }; template<int D> struct select<0, D, true> { static int const value = 0; }; int main() { std::cout << select<1, 3>::value; // 0 std::cout << select<7, 3>::value; // 6 std::cout << select<10, 3>::value; // 9 } 
+4
source

Inheritance works quite well:

 template<int N> struct Junk : private JunkBase < N % 5 > { }; template<int N> struct JunkBase { static int foo() { // stuff return Junk<N - 1>::foo(); } }; template< > struct JunkBase<0> { static int foo() { return 0; } }; 

You may need to pass N to JunkBase :: foo if you need N / 5 too.

+2
source

I would not call it elegant, but here my version of your code used only templates for calculation (along with the test thing) -

 #include <iostream> template < int N > struct JunkDivBy5 { static int foo() { return N; } }; template < int N > struct Junk { template < int N1 > struct _JunkCond { enum { val = ( N1 != 1 && ( N1 - 1 ) % 5 == 0 ) ? 1 : 0 }; }; template < int M, int N1 > struct _JunkBranch { /* Error */ }; template < int N1 > struct _JunkBranch< 1, N1 > { typedef JunkDivBy5< N1 - 1 > Type; }; template < int N1 > struct _JunkBranch< 0, N1 > { typedef Junk< N1 - 1 > Type; }; static int foo() { return _JunkBranch< _JunkCond< N >::val, N >::Type::foo(); } }; template <> struct Junk< 0 > { static int foo() { return 0; } }; int main( int argc, char *argv[] ) { std::cout << Junk< 0 >::foo() << std::endl; std::cout << Junk< 5 >::foo() << std::endl; std::cout << Junk< 7 >::foo() << std::endl; std::cout << Junk< 25 >::foo() << std::endl; } 
0
source

All Articles