sprout::apply_visitor で static_visitor に依存しないアプローチ
Sprout.Variant の apply_visitor に『static_visitor を継承していない(result_type が定義されていない) Visitor を渡したい!』というムチャぶりをした結果、いくつかの代案が出たので覚書。
1.文字列にして返す
言葉通り文字列にして返してあとから復元します。
#include <sprout/variant.hpp> #include <sprout/string.hpp> struct twice{ template<typename T> constexpr auto operator ()(T const& t) ->decltype(sprout::to_string(t + t)) const{ return sprout::to_string(t + t); } }; int main(){ typedef sprout::variant<int, double, sprout::string<16>> var; { constexpr var v{42}; constexpr auto result = sprout::apply_visitor(twice{}, v); static_assert(result == "84", ""); static_assert(sprout::from_string<int>(result) == 84, ""); } { constexpr var v{1.25}; constexpr auto result = sprout::apply_visitor(twice{}, v); static_assert(result == "2.500000", ""); static_assert(sprout::from_string<double>(result) == 2.5, ""); } { constexpr var v{ sprout::stretch<16>("homu") }; constexpr auto result = sprout::apply_visitor(twice{}, v); static_assert(result == "homuhomu", ""); } return 0; }
実用性は兎も角として、アプローチとしては面白いですね。
2.Variant を返す
Variant の各型を適用した戻り値型の Variant を返します。
この場合は、static_visitor
#include <sprout/variant.hpp> #include <sprout/string.hpp> struct twice : sprout::static_variant_visitor{ template<typename T> constexpr auto operator ()(T const& t) ->decltype(t + t) const{ return t + t; } }; int main(){ typedef sprout::variant<int, double, sprout::string<16>> var; { constexpr var v{42}; constexpr auto result = sprout::apply_visitor(twice{}, v); static_assert(sprout::get<0>(result) == 84, ""); static_assert(result == 84, ""); } { constexpr var v{1.25}; constexpr auto result = sprout::apply_visitor(twice{}, v); static_assert(sprout::get<1>(result) == 2.5, ""); static_assert(result == 2.5, ""); } { constexpr var v{ sprout::stretch<16>("homu") }; constexpr auto result = sprout::apply_visitor(twice{}, v); static_assert(sprout::get<2>(result) == "homuhomu", ""); static_assert(result == sprout::stretch<32>("homuhomu"), ""); } return 0; }
3.sprout::as_variant_visitor を使用する
動作的には 2. と同じように Variant を返すのですが、static_variant_visitor を継承するのではなくて、as_variant_visitor でラップすることで非侵入的に使用します。
#include <sprout/variant.hpp> #include <sprout/string.hpp> struct twice{ template<typename T> constexpr auto operator ()(T const& t) ->decltype(t + t) const{ return t + t; } }; int main(){ typedef sprout::variant<int, double, sprout::string<16>> var; { constexpr var v{42}; constexpr auto result = sprout::apply_visitor(sprout::as_variant_visitor(twice{}), v); static_assert(sprout::get<0>(result) == 84, ""); static_assert(result == 84, ""); } { constexpr var v{1.25}; constexpr auto result = sprout::apply_visitor(sprout::as_variant_visitor(twice{}), v); static_assert(sprout::get<1>(result) == 2.5, ""); static_assert(result == 2.5, ""); } { constexpr var v{ sprout::stretch<16>("homu") }; constexpr auto result = sprout::apply_visitor(sprout::as_variant_visitor(twice{}), v); static_assert(sprout::get<2>(result) == "homuhomu", ""); static_assert(result == sprout::stretch<32>("homuhomu"), ""); } return 0; }
個人的にはこれが一番しっくり来ますね。
と、いう感じでいくつか考えてもらいました。