Consider the following template, intended on declaring some State::Machine
:
enum Strategy {
Breadth,
Depth,
Heuristic,
};
template<class Map, Strategy Strategy = Depth>
struct Machine;
If we would like to enforce some constraints on the Map
type, so that implementations satisfy necessary concepts, we have:
template <Range::Type Source, Comparable Constraint, class Result, Transition<Source, Constraint, Result> Transition, Range::Of<Transition> Transitions, Map<Constraint, Transitions> Map, Strategy Strategy = Strategy::Depth>
class Machine {
};
Where Source
is some container
like std::vector
, Constraint
is some comparable struct == struct -> bool
, Transition
is some lambda(Source) -> Product
and Transitions
is some container
of Transition
.
Declaring this type is now exhausting:
auto transition = [](std::string source) {
return State::Product<std::string, State, State> {
.source = source,
.state = State::Start,
.product = State::Start,
};
};
static_assert(Transition<decltype(transition), std::string, State, State>);
std::map<State, std::set<decltype(transition)>> map = {
{State::Start, {transition}}
};
State::Machine<std::string, State, State, decltype(transition), std::set<decltype(transition)>, decltype(map)> machine;
Is there a way to have all the concepts be required with only one type parameter
State::Machine<decltype(map)> machine;
Similar to how it was before any concepts were required?
CodePudding user response:
Most types expose their "subtypes".
std::map
has key_type
and mapped_type
for example.
(You can create traits to extract template parameter if needed BTW, if type doesn't provide such typedef
).
Then you might use constraint on those sub-types, something like:
template <typename Map, Strategy Strategy = Strategy::Depth>
requires(Comparable<typename Map::key_type>
&& IsATransition<typename Map::mapped_type>)
class Machine
{
// ...
};