I have a following class:
template<typename Population, typename... Operators> class GA
{
public:
template<typename Evaluator,
typename std::enable_if_t<
std::is_same_v<Evaluator, Evaluator<Operators...>>>>
void EvaluatePopulation(Evaluator& evaluator)
{
evaluator.Evaluate();
}
};
This doesn't compile, because of incorrect EvaluatePopulation
declaration.
How do I specify that EvaluatePopulation
method can be called only with Evaluator
class that was initialized with the same Operators...
as the GA
class?
How do I specify that
EvaluatePopulation
method can be called only withEvaluator
class that was initialised with the sameOperators...
as theGA
class?
The trick is to use a template template parameter so that you “unpack” the evaluator’s template arguments to match the GA’s pack. For example, you can write:
template<typename Population, typename... Operators>
class GA
{
public:
template<template<typename...> class EvaluatorT>
void EvaluatePopulation(EvaluatorT<Operators...>& evaluator)
{
evaluator.Evaluate();
}
};
((See live demo))
Alternatively, using c++20's concepts, which gives clearer error messages:
// Ensures Evaluator is instantiated with exactly Operators...
template<typename T, typename... Args>
constexpr bool is_evaluator_for_v = false;
template<template<typename...> class EvaluatorT, typename... Ops>
constexpr bool is_evaluator_for_v<EvaluatorT<Ops...>, Ops...> = true;
template<typename Evaluator, typename... Operators>
concept EvaluatorFor = is_evaluator_for_v<Evaluator, Operators...>;
template<typename Population, typename... Operators> class GA
{
public:
template<typename Evaluator> requires EvaluatorFor<Evaluator, Operators...>
void EvaluatePopulation(Evaluator& evaluator)
{
evaluator.Evaluate();
}
};
((See live demo))