Noone AtAll
Noone AtAll

Reputation: 385

Creating multiple class implemetations based on template parameter

I have a templated class G:

template<int I>
class G {}

And it's so happens that I need 2 implementations based on that int I

If it was a single value, I would always be able to do:

template<>
class G<int Specific_I>
{
    /*Implementation for that I*/
}

If I had single condition, which shows to use implementation_1 if true and implementation_2 if false, I could've used advice given here


But, my situation is more general.

Let's say I defined conditions on I for each implementation:

template<int I>
constexpr bool Condition_1 = /*whatever*/;

template<int I>
constexpr bool Condition_2 = /*whatever_v2*/;

This allows for easy readability and expansion as needed
And if I get an error due to none or multiple of conditions applying for specific I when called in program, I'm fine with that

Obvious choice is to use std::enable_if_t

template<int I,
enable_if_t<Condition_1<I>>
        >
class G
{
    /*Implementation based on Condition_1*/
}

template<int I,
enable_if_t<Condition_2<I>>
        >
class G
{
    /*Implementation based on Condition_2*/
}

But this causes an error

template parameter ‘typename std::enable_if<Condition_1<I>, void>::type <anonymous>’|

redeclared here as ‘typename std::enable_if<Condition_2<I>, void>::type <anonymous>’|

Where have I made mistake and how do I fix that?

Upvotes: 3

Views: 74

Answers (2)

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136425

You don't need std::enable_if for this problem. Since your conditions are independent they should initialize a different template parameter:

template<int I, bool C1 = Condition_1<I>, bool C2 = Condition_2<I>>
struct G;

// Specializations for different conditions.
template<int I> struct G<I, false, false> { /*...*/ };
template<int I> struct G<I, false,  true> { /*...*/ };
template<int I> struct G<I,  true, false> { /*...*/ };
template<int I> struct G<I,  true,  true> { /*...*/ };

Alternatively, you can compose conditions into one parameter:

template<int I, unsigned C = (Condition_1<I> | Condition_2<I> * 2)>
struct G;

// Specializations for different conditions.
template<int I> struct G<I, 0> { /*...*/ };
template<int I> struct G<I, 1> { /*...*/ };
template<int I> struct G<I, 2> { /*...*/ };
template<int I> struct G<I, 3> : G<I, 2> { /*...*/ }; // Same as G<I, 2>.

Upvotes: 2

Your mistake is that you didn't adjust the primary template to use the idiom correctly. If you want to add those enable_if's that resolve to void, the primary template declaration needs a type parameter in that place:

template<int I, typename = void>
class G; // Or static_assert in the definition. Whichever flavor you prefer.

template<int I>
class G< I, enable_if_t<Condition_1<I>> >
{
    /*Implementation based on Condition_1*/
};

template<int I>
class G< I, enable_if_t<Condition_2<I>> >
{
    /*Implementation based on Condition_2*/
};

Note: the default argument must be void for your specializations with the condition to match. This will of course result in an error when both conditions hold, but you did assert that's fine with you, so there you go.

Upvotes: 3

Related Questions