c++概念:检查是否从模板形参未知的模板化类派生



有没有一种方法可以使用c++的概念来要求一个类是从一个模板化的类派生出来的,而这个模板化的类的模板形参又是从另一个模板化的类派生出来的?

的例子:

template <class T>
class A{};
template <class T>
class B{};
class X{};
class Y : public A<X> {};
class Z : public B<Y> {};

我如何检查B,Tstd::is_base_of<A<X>,T>形式的某些X而不指定X是什么?我不想将X添加到B的模板参数列表中,因为我不想在B派生的每个实例中更改代码(例如,class Z的最后一行)。

如果你想检查A的专门化,这并不太难。

template <class C>
concept A_ = requires(C c) {
// IILE, that only binds to A<...> specialisations
// Including classes derived from them
[]<typename X>(A<X>&){}(c);
};

lambda基本上只是一个函数的简写,它被重载以接受A专门化。从这种专门化派生的类也算在内。我们使用我们正在检查的类型的参数调用lambda…约束是true还是false取决于调用是否有效(参数被接受)。

然后,把它插进去:

template <A_ T>
class B{};

现在它正在工作。

受@StoryTeller - Unslander Monica的启发,我写了更多的通用概念,可以为任何期望的模板类定制。

但是,您可能首先要问自己,限制模板类型是否真的有意义?它使你的设计不那么灵活,这样你就不能稍后为单元测试注入模拟类型。我的意思是,通常最好写一个概念,它要求你的类型遵守一些特定的契约(包含一些成员函数、常量、别名等),而不是实际上。一个具体类。

话虽如此,这里是一般的解决方案:

/**
* @brief Checks if class type Specialisation (the implicit concept 
* argument) is indeed a specialisation of TemplateClass type
* (e.g. satisfied for TemplateClass=SomeLibrary and 
* Specialisation=SomeLibrary<A, B>). Also accepts classes 
* deriving from specialised TemplateClass.
*
* @tparam PartialSpecialisation optional partial specialisation 
* of the TemplateClass to be required
*/
template<class Specialization, template<typename> class TemplateClass,
typename ...PartialSpecialisation>
concept Specializes = requires (Specialization s) {
[]<typename ...TemplateArgs>(
TemplateClass<PartialSpecialisation..., TemplateArgs...>&){}(s);
};

然后对于你的用例:

template <Specializes<A> T>
class B{};

,甚至需要特定的部分专门化所需的类:

template<typename ...Args>
struct SomeBase {};
struct A {};
struct B {};
template<Specializes<SomeBase, A> BaseT>
struct Container {};
Container<SomeBase<A, B>> {};   // fine, first template arg is A
Container<SomeBase<B, B>> {};   // error, first template arg isn't A

查看这里的工作实例。

最新更新