Specifying a concept for a type that has a member function template using Concepts Lite
c++, c++-concepts, higher-kinded-types
Solution
Let's think about the requirements you want from your comment:
// 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)
While Concepts requires us to base our constraints around concrete types, we can be smart in our selection of which concrete types we use. What do you mean by `U` is any type. Really any type at all, whatsoever? Think about the smallest possible set of constraints you have on `U` and let's build a type that satisfies them. This is known as an archetype of `U`.
My goto first thought for "any type" would actually be a semiregular type. A type that is default constructible, copyable, and assignable. All the normal goodies:
namespace archetypes {
// private, only used for concept definitions, never in real code
struct Semiregular { };
}
`archetypes::Semiregular` is a concrete type, so we can use it to build a concept:
template <template <class> class HKT, class T>
concept bool HKTWithTemplateMemberFunctionF =
requires(HKT<T> h, archetypes::Semiregular r) {
{h.F(r)} -> HKT<archetypes::Semiregular>
};
`archetypes::Semiregular` is a private type. It should not be known to `HKT`, and so if `h.F(r)` is well-formed and returns a type convertible to `HKT<archetypes::Semiregular>`, it's almost certainly a member function template.
The question then is, is this a good archetype? Do we need `U` to be semiregular, or would irregular types work too? The fewer operations that you need, the fewer should be present in your archetype. Maybe all you need is that `U` is movable:
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) {
{ h.F(m) } -> HKT<archetypes::Moveable>
};
We're testing the same idea - invoking `F()` with a type that isn't well-known and excepting the return type to reflect that, hence requiring it to be a function template. But now we're giving less functionality to the type. If `F()` works on any, it'll work on `archetypes::Moveable`.
Keep iterating on this idea until you've really pared down the required functionality to the bare minimum. Maybe you don't even need the archetype to be destructible? Writing archetypes is hard, but in cases like this, it's important to get right.
Problem
I'm trying to specify a concept to constrain a higher kinded type that has a member function template using Concepts Lite. However I am not able to find inside the technical specification or the tutorial a clause dealing with templated statements inside a concept. How is this done? Example: suppose I have the higher kinded type `HKT` with a member function template `F`: ``` template<class T> struct HKT { template<class U> // this looks like e.g. rebind in std::allocators auto F(U) -> HKT<U>; }; ``` and that now I want to specify a concept for constraining these higher kinded types: ``` 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? h.F(std::declval<U>()) -> HKT<U>; } } ``` Note that I could do something like: ``` template <template <class> class HKT, class T, class U> concept HKTWithTemplateMemberFunctionF { return requires(HKT<T> h) { h.F(std::declval<U>()) -> HKT<U>; } } ``` but this means that I need to know `U` at constraint site. I don't really care if substitution for a given `U` fails or not although I can see why this could be a problem: e.g. apply a constraint to be sure your function doesn't fail and then fails cause the constraint was satisfied but at instantiation time substitution failed in the member function template (would it help if the member function template was constrained?).