I'm new in advanced usage of templates and concepts, so here is a liitle bit complex problem:
I have some
Traitsconcept of many traits for each ofSourceclasses:template<typename _Traits> concept Traits = requires { std::same_as<std::decay_t<decltype(_Traits::token)>, std::string_view>; };I have some template class that uses this concept to handle
object_onewith various traits (for example, half ofSourceclasses returnsobject_one):template <concepts::Traits _Traits> class Object_one_handler final { static std::string handle_object(const object_one& obj) {/*...*/} };Then I have
Objects_handlersconcept of handlers for various objects from set{object_one, object_two, object_three}from variousSourceswith theirTraits:template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object> concept Objects_handlers = requires(const _Object& obj) { // has handle_object method { _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>; };Finally, I creating some
databasewith specified as template parameterObject_handler:template<concepts::Objects_handlers _handler> class database {...};
(Actually all of concepts have additional requirements, but it doesn't matter here)
So problem is in last Objects_handlers concept:
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
^^^^^^^
};
I can't check _Objects_handlers method without template parameter (obviously) and I can't properly set the template parameter which must be one of Traits.
How can I do that?
And actually it may be problem in usage of Objects_handlers in template of database class, so one more question: how to use it?
P.S. It can be XY problem or not about concepts at all... Maybe composition with strategy pattern will be more usefull, but still want try to create this maybe useless, but workable concept.
CodePudding user response:
Let's reduce this problem a lot.
template <typename T>
struct C {
void f();
};
Now, your goal is to write a concept that takes any class template (e.g. C) and checks that every specialization of it has a nullary member function named f.
template <template <typename> class Z>
concept HasF = requires (Z<???> z) {
z.f();
};
The problem is - class templates in C just don't work like this. Even for a particular class template, like C, you can't require that every specialization has f. There's no way to ensure that like somebody, somewhere, didn't add:
template <> struct C<std::vector<std::list<std::deque<int>>>> { };
All you can do is check that a specific type has a nullary member function named f. And that's:
template <typename T>
concept HasF = requires (T t) { t.f(); };
The type-constraint syntax, template <Concept T>, is only available for concepts that constrain types, not concepts that constrain templates or values.
