根据模板参数创建多个 class 实现

Creating multiple class implemetations based on template parameter

我有一个模板 class G:

template<int I>
class G {}

碰巧我需要 2 个基于 int I

的实现

如果它是单个值,我总是能够做到:

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

如果我有单一条件,显示如果为真则使用 implementation_1,如果为假则使用 implementation_2,我可以使用给出的建议 here


但是,我的情况比较一般。

假设我在 I 上为每个实现定义了条件:

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

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

这样可以根据需要轻松阅读和扩展
如果在程序中调用时由于 none 或申请特定 I 的多个条件而出现错误,我可以接受

显而易见的选择是使用 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*/
}

但这会导致错误

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>’|

我哪里出错了,我该如何改正?

你的错误是你没有调整主模板来正确使用成语。如果你想添加那些解析为 voidenable_if,主模板声明在那个地方需要一个类型参数:

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*/
};

注意:默认参数必须是 void 才能使您的专业化条件匹配。当两个条件都成立时,这当然会导致错误,但您确实断言这对您来说没问题,所以就这样吧。

你不需要std::enable_if来解决这个问题。由于您的条件是独立的,因此它们应该初始化不同的模板参数:

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> { /*...*/ };

或者,您可以将条件组合成一个参数:

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>.