I'm new in advanced usage of templates and concepts, so here is a liitle bit complex problem:
I have some
Traits
concept of many traits for each ofSource
classes: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_one
with various traits (for example, half ofSource
classes returnsobject_one
):template <concepts::Traits _Traits> class Object_one_handler final { static std::string handle_object(const object_one& obj) {/*...*/} };
Then I have
Objects_handlers
concept of handlers for various objects from set{object_one, object_two, object_three}
from variousSources
with 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
database
with 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.