将类型模板参数限制为仅采用特定模板的实例化

时间:2017-12-25 09:09:54

标签: c++ templates

用于约束类型模板参数的惯用方法是什么,以便它只接受特定模板的实例化?

如,

template<typename P>
class C {
   C() = default;
   ...
};

template<typename T>
class Accepted {
   ...
};

template<typename T>
class Other {
   ...
};

C<Accepted<float>> obj1;   // should compile
C<Accepted<int>>   obj2;   // should compile
C<Other<int>>      obj3;   // should not compile
C<double>          obj4;   // should not compile

2 个答案:

答案 0 :(得分:3)

专业化是答案。

template<typename P> class C;

template<typename T>
class Accepted {
   ...
};

template<typename P>
class C<Accepted<P>> {
   C() = default;
   ...
};

以上使得C<Accepted<T>>格式正确,因为它在实例化时选择了特化。虽然任何其他C<T>选择了未定义的主要特化,因此不会编译。

答案 1 :(得分:2)

我在不了解更多相关背景的情况下看到了两个可能的答案。

template<typename T> class C;
template<template<typename> typename TT, typename T> class C<TT<T>> {
... static_assert(std::is_same<TT<T>, Accepted<T>>::value, "The given type is not an instantiation of Accepted!"); ...
}

这只是非常有用 - 接受的特别之处是什么?您可能有第二个模板,例如SortedAccepted<T>,符合相同要求,但您已着手将模板参数约束为Accepted<T>

一种选择是将Accepted设计为契约,以便它的派生必须满足与Accepted本身相同的约束:

template<template<typename> typename TT, typename T> class C {
... static_assert(std::is_base_of<Accepted<T>, TT<T>>::value,
    "The given type is not a derivation of Accepted!"); ...
};

这是从设计原则得出的结论,即Accepted应该通过其派生来扩展,但不能被修改。从前面的示例中,可能Accepted需要具有幂等“排序”方法 - accepted.sort().sort() == accepted.sort() - 而SortedAccepted隐式保留此属性,但另外提供sorted_accepted.sort() == sorted_accepted。在允许排序接受的地方你没有什么可失去的,只要你期望接受,但可以获得很多!

如果我理解你的问题,你可能会对Traits and Concepts感兴趣。

<type_traits>Boost's extensions中看到的类型特征是reified合同,提供有关集合共享特征,这些特征的表达式等的编译时保证。例如S s; T t; auto u = s + t std::is_arithmetic<S>::valuestd::is_arithmetic<T>::value为真,保证std::is_arithmetic<decltype(u)>::value为真;如果是is_floating_point,那么你也是。

Concepts是类型特征的下一个逻辑步骤:实质上是特征的reified 要求。 (参见:'Concepts Lite')