好吧标题党了,所谓“模式匹配”只是给把std::visit
包装了一下,只能匹配类型,功能远不及其他语言。
效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| using T = std::variant<int, double>; T v = 1.414;
T v2 = Match{v}( [](int x) -> T { std::cout << "get int value: " << x << std::endl; return x * x; }, [](double x) -> T { std::cout << "get double value: " << x << std::endl; return x * x; } );
Match{v2}( [](auto x) { std::cout << x << std::endl; } );
Match{std::move(ret)}( [&](Context::Int val) { str += std::format(" li a0, {}\n", val); }, [&](Context::Stack st) { str += std::format(" lw a0, {}(sp)\n", st); }, [&](Context::Reg&& reg) { str += std::format(" mv a0, {}\n", reg); }, [&](auto&& s) { throw std::runtime_error("invalid type"); } );
|
看着还是很像模式匹配的,可读性比std::visit
头重脚轻的参数高点
首先定义一个辅助类,将不同类型的参数匹配到具体不同的operator()
1 2 3 4 5
| template <typename... Ts> struct Visitor : Ts... { using Ts::operator()...; };
template <typename... Ts> Visitor(Ts...) -> Visitor<Ts...>;
|
然后是Match
类,存一个引用以便于在operator()
中调用std::visit
1 2 3 4 5 6 7 8 9 10 11 12
| template <typename T> struct Match { T value; Match(T&& value) : value(std::forward<T>(value)) {} template <typename... Ts> auto operator()(Ts&&... params) { return std::visit(Visitor{std::forward<Ts>(params)...}, std::forward<T>(value)); } template <typename... Ts> auto operator()(Visitor<Ts...> visitor) { return std::visit(visitor, std::forward<T>(value)); } };
template <typename T> Match(T&&) -> Match<T&&>;
|