История изменений
Исправление Siborgium, (текущая версия) :
Кратко: https://godbolt.org/z/K96z6onrb
Для Ъ:
/* Визитор, пишется один раз в хэдере */
template <typename ... Ts> struct Overloaded: Ts... { using Ts::operator()...; };
template <typename ... Ts> Overloaded(Ts...) -> Overloaded<Ts...>;
/* Актуальный код */
template <typename T>
concept HasToString = requires (T trait, std::string& result, const State & state) {
result += trait.toString(state);
};
template <typename ... Traits>
void traitsToString(const State& voxel, std::string& result, Traits&& ... traits) {
Overloaded impl {
[&](HasToString auto&& trait){ result += trait.toString(voxel); },
[](auto&&){ /* noop */ }
};
(impl(traits), ...);
}
Можно, конечно, и без визитора, а просто через if constexpr
, но там нужно будет remove_cvref_t
делать.
Кстати, делать string += toString
так себе идея. Лучше уж тогда stringstream
и передавать по ссылке в toString
, чтобы строки лишний раз не создавать.
Исходная версия Siborgium, :
Кратко: https://godbolt.org/z/K96z6onrb
Для Ъ:
/* Визитор, пишется один раз в хэдере */
template <typename ... Ts> struct Overloaded: Ts... { using Ts::operator()...; };
template <typename ... Ts> Overloaded(Ts...) -> Overloaded<Ts...>;
/* Актуальный код */
template <typename T>
concept HasToString = requires (T trait, std::string& result, const State & state) {
result += trait.toString(state);
};
template <typename ... Traits>
void traitsToString(const State& voxel, std::string& result, Traits&& ... traits) {
Overloaded impl {
[&](HasToString auto& trait){ result += trait.toString(voxel); },
[](auto&&){ /* noop */ }
};
(impl(traits), ...);
}
Можно, конечно, и без визитора, а просто через if constexpr
, но там нужно будет remove_cvref_t
делать.
Кстати, делать string += toString
так себе идея. Лучше уж тогда stringstream
и передавать по ссылке в toString
, чтобы строки лишний раз не создавать.