使用Concepts Lite指定具有成员函数模板的types的概念

我试图指定一个概念来约束一个更高级的使用Concepts Lite的成员函数模板。 但是,我无法在技术规范或教程中find一个概念内处理模板语句的子句。

这是怎么做的?

例如:假设我有一个成员函数模板F

 template<class T> struct HKT { template<class U> // this looks like eg rebind in std::allocators auto F(U) -> HKT<U>; }; 

而现在我想指定一个概念来约束这些更高级的kindedtypes:

 template <template <class> class HKT, class T> concept HKTWithTemplateMemberFunctionF { return requires(HKT<T> h) { // HKT<T> is a type, h is an object // HKT<T> needs to have a member function template that // returns HTK<U> where the type U is to be deduced and // it can be any type (it is unconstrained) template<class U> // is there a syntax for this? hF(std::declval<U>()) -> HKT<U>; } } 

请注意,我可以这样做:

 template <template <class> class HKT, class T, class U> concept HKTWithTemplateMemberFunctionF { return requires(HKT<T> h) { hF(std::declval<U>()) -> HKT<U>; } } 

但是这意味着我需要在约束站点了解U

我真的不在乎是否replace给定的U失败,但我可以看出为什么这可能是一个问题:例如,应用一个约束来确保你的函数没有失败,然后失败,导致约束满足,但在实例化时间replace在成员函数模板中失败(如果成员函数模板受到约束,会有帮助吗?)。

让我们从你的评论中考虑你想要的要求:

 // HKT<T> needs to have a member function template that // returns HTK<U> where the type U is to be deduced and // it can be any type (it is unconstrained) 

虽然概念要求我们将约束条件放在具体types的基础上,但我们可以在select使用哪种具体types时做出明智的select。 U是什么意思? 真的是任何types的,不pipe怎样? 想想你在U上的最小可能的约束条件,让我们build立一个满足它们的types。 这被称为U原型

我首先想到的“任何types”实际上是一个半规则types。 一种默认可构造,可复制和可分配的types。 所有正常的好东西:

 namespace archetypes { // private, only used for concept definitions, never in real code struct Semiregular { }; } 

archetypes::Semiregular是一个具体types,所以我们可以用它来构build一个概念:

 template <template <class> class HKT, class T> concept bool HKTWithTemplateMemberFunctionF = requires(HKT<T> h, archetypes::Semiregular r) { {hF(r)} -> HKT<archetypes::Semiregular> }; 

archetypes::Semiregular是一个私人types。 它不应该被HKT知道,所以如果hF(r)是格式良好的,并且返回一个可转换为HKT<archetypes::Semiregular> ,它几乎肯定是一个成员函数模板。

那么问题是,这是一个很好的原型吗? 我们是否需要U是半规则的,还是不规则types也会起作用? 您需要的操作越less,原型中应该出现的就越less。 也许你需要的只是U是可移动的:

 namespace archetypes { // private, only used for concept definitions, never in real code struct Semiregular { }; struct Moveable { Moveable() = delete; Moveable(Moveable&& ) noexcept(false); Moveable(Moveable const& ) = delete; ~Moveable() = default; Moveable& operator=(Moveable const& ) = delete; Moveable& operator=(Moveable&& ) noexcept(false); }; } template <template <class> class HKT, class T> concept bool HKTWithTemplateMemberFunctionF = requires(HKT<T> h, archetypes::Moveable m) { { hF(m) } -> HKT<archetypes::Moveable> }; 

我们正在testing相同的想法 – 调用F()的types,这是不知名的,除了返回types反映,因此要求它是一个函数模板。 但是现在我们正在给该types提供更less的function。 如果F()适用于任何 ,它将工作在archetypes::Moveable

不断迭代这个想法,直到你真正地将所需的function降到最低。 也许你甚至不需要原型被破坏? 编写原型很难,但是在这种情况下,正确的做法很重要。

长话短说,现在你(我?)必须提供一个具体的U

 template <template <class> class HKT, class T, class U = T> concept HKTWithTemplateMemberFunctionF { return requires(HKT<T> h) { // HKT<T> is a type, h is an object hF(std::declval<U>()) -> HKT<U>; } } 

因为编译器不能certificate成员函数模板可能存在的所有types的U ,也就是说,下面是无望的:

 template <template <class> class HKT, class T> concept HKTWithTemplateMemberFunctionF { return requires(HKT<T> h) { template<class U> // for all those Us that haven't been written yet... hF(std::declval<U>()) -> HKT<U>; } } 

在一个假设的5分钟概念精简实现中,我们可以将U 仅仅稍微限制一下

 template <template <class> class HKT, class T, InputIterator U = InputIterator() /* imaginary syntax */ > concept HKTWithTemplateMemberFunctionF { return requires(HKT<T> h) { hF(std::declval<U>()) -> HKT<U>; // Is InputIterator enough to instantiate F? } } 

编译器只需要检查一个InputIterator的模型是否足以实例化hF ,即使hF没有被约束,这也是可能的! 另外提供U只是检查它是否为hF ,因为InputIterator已经足够了,甚至不需要尝试检查hF是否为U 这可以用来优化编译时的性能和…

…可能会以令人惊讶的方式与SFINAE进行交互,因为AFAIK可以有一个概念重载函数(例如用于InputIterator )接受除一个之外的所有input迭代器(SFINAE!为什么会有人这么做?!)通过概念检查,但在实例化时间吹…悲伤。