根据模板参数创建多个 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>’|
我哪里出错了,我该如何改正?
你的错误是你没有调整主模板来正确使用成语。如果你想添加那些解析为 void
的 enable_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>.
我有一个模板 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>’|
我哪里出错了,我该如何改正?
你的错误是你没有调整主模板来正确使用成语。如果你想添加那些解析为 void
的 enable_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>.