假设变体中的每种类型都有一些字段std::string_view token;
(无论是在每个类型中写出还是来自一个共同的,不一定是多态的,基类取决于您),您可以编写如下访问器:
std::string_view getToken(const Node& node)
{
return std::visit([](const auto& n) { return n.token; }, node);
}
https://godbolt.org/z/B8tAdY
请注意,您不必手动添加重载 - auto
lambda 中的 lambda 本质上使 lambda 成为模板,因此您只需依赖编译时多态性。你最终得到了一个不错的跳转表(每个只返回适当的成员偏移量):
std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 0ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&): # @"std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 0ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)"
mov rax, qword ptr [rsi + 8]
mov rdx, qword ptr [rsi + 16]
ret
std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 1ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&): # @"std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 1ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)"
mov rax, qword ptr [rsi + 16]
mov rdx, qword ptr [rsi + 24]
ret
std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 2ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&): # @"std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 2ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)"
mov rax, qword ptr [rsi + 8]
mov rdx, qword ptr [rsi + 16]
ret
std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 3ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&): # @"std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 3ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)"
mov rax, qword ptr [rsi + 16]
mov rdx, qword ptr [rsi + 24]
ret
std::__detail::__variant::__gen_vtable<true, std::basic_string_view<char, std::char_traits<char> >, getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&>::_S_vtable:
.quad std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 0ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)
.quad std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 1ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)
.quad std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 2ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)
.quad std::__detail::__variant::__gen_vtable_impl<true, std::__detail::__variant::_Multi_array<std::basic_string_view<char, std::char_traits<char> > (*)(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)>, std::tuple<std::variant<Add, Sub, Mul, Div> const&>, std::integer_sequence<unsigned long, 3ul> >::__visit_invoke(getToken(std::variant<Add, Sub, Mul, Div> const&)::$_0&&, std::variant<Add, Sub, Mul, Div> const&)
可悲的是,使用通用基类不会导致编译器意识到所有案例都有相同的代码 - 你仍然保留跳转表:https ://godbolt.org/z/GTyNgP
理论上,您可以使用自定义的类似变体的类型擦除数据结构,它知道所有具有公共基类的类型并通过它来代替。但这朝着只拥有一个NodeBase
具有公共接口等的类的方向发展。