Вы можете значительно упростить посетителя, используя if constexpr
:
struct visitor{
template<typename T>
void operator()(T& t) {
if constexpr (has_reduce_thrust<T>::value) {
t.reduce_thrust(perc);
reduced_thrust = true;
}
else {
reduced_thrust = false;
}
}
int perc = 0;
bool reduced_thrust = false;
};
Затем вы можете абстрагироваться дальше, приняв любой предикат и две функции для любой ветви if constexpr
:
template <template <class, class... /*SFINAE friendly*/> class TypePred,
class MatchedFunc, class UnmatchedFunc>
class predicated_visitor {
public:
predicated_visitor(MatchedFunc matchedFunc, UnmatchedFunc unmatchedFunc)
: _matchedFunc(matchedFunc), _unmatchedFunc(unmatchedFunc) {}
template <typename T>
void operator()(T& t) {
if constexpr (TypePred<T>::value)
_matchedFunc(t);
else
_unmatchedFunc(t);
}
private:
MatchedFunc _matchedFunc;
UnmatchedFunc _unmatchedFunc;
};
template <template <class, class... /*SFINAE friendly*/> class TypePred,
class F1, class F2>
auto makePredicatedVisitor(F1 f1, F2 f2) {
return predicated_visitor<TypePred, F1, F2>(f1, f2);
}
Полученный код довольно приятный, я чувствую:
void reduce_speed(std::variant<simple_engine1, simple_engine2, complex_engine1,
complex_engine2>* var_engine) {
int perc = 47;
bool reducedThrust = false;
auto reduceableThrustAction = [perc, &reducedThrust](auto& t) {
t.reduce_thrust(perc);
reducedThrust = true;
};
auto alternativeAction = [](auto& t) {
}; // Could explicitly set reduceThrust to false for clarity.
auto thrust_visitor = makePredicatedVisitor<has_reduce_thrust>(
reduceableThrustAction, alternativeAction);
std::visit(thrust_visitor, *var_engine);
if (reducedThrust) {
std::cout << "reduced thrust\n";
} else {
std::cout << "activating reverse engines\n";
}
}
Демонстрация
Этот пример компилируется, по сути, в тот же код сборки, что и ваш, но может бытьповторно использовать любым способом, который вам нравится.
Прошу прощения за непоследовательную капитализацию ...