无法编译以下代码以访问结构的变体
Posted
技术标签:
【中文标题】无法编译以下代码以访问结构的变体【英文标题】:cannot compile below code for visiting a variant of struct 【发布时间】:2018-11-15 03:47:26 【问题描述】:我尝试编写一个非常简单的变体和访问者实现,如下所示,但出现编译错误,我无法弄清楚原因。
#include <variant>
#include <string>
#include <iostream>
struct foo
std::string s;
;
struct bar
double s;
;
using var = std::variant<foo, bar>;
struct visitor
template <class T>
auto operator()(const T v) -> decltype(v.s)
return v.s;
;
int main()
foo f;
f.s = 3.0;
var x = f;
auto xs = std::visit(visitor, x);
std::cout<<xs<<std::endl;
这个错误太长了,而且复杂到让我作为 c++11+ 的新手感到困惑
In file included from main.cpp:1:
/usr/local/include/c++/8.1.0/variant: In instantiation of 'static constexpr auto std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...)>, std::tuple<_Rest ...>, std::integer_sequence<long unsigned int, __indices ...> >::_S_apply() [with _Result_type = std::__cxx11::basic_string<char> _Visitor = visitor&&; _Variants = std::variant<foo, bar>&; long unsigned int ...__indices = 1]':
/usr/local/include/c++/8.1.0/variant:825:61: required from 'static constexpr void std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...), __dimensions ...>, std::tuple<_Variants ...>, std::integer_sequence<long unsigned int, __indices ...> >::_S_apply_single_alt(_Tp&) [with long unsigned int __index = 1; _Tp = std::__detail::__variant::_Multi_array<std::__cxx11::basic_string<char> (*)(visitor&&, std::variant<foo, bar>&)> _Result_type = std::__cxx11::basic_string<char> _Visitor = visitor&&; long unsigned int ...__dimensions = 2; _Variants = std::variant<foo, bar>&; long unsigned int ...__indices = ]'
/usr/local/include/c++/8.1.0/variant:813:39: required from 'static constexpr void std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...), __dimensions ...>, std::tuple<_Variants ...>, std::integer_sequence<long unsigned int, __indices ...> >::_S_apply_all_alts(std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...), __dimensions ...>, std::tuple<_Variants ...>, std::integer_sequence<long unsigned int, __indices ...> >::_Array_type&, std::index_sequence<__indices ...>) [with long unsigned int ...__var_indices = 0, 1; _Result_type = std::__cxx11::basic_string<char> _Visitor = visitor&&; long unsigned int ...__dimensions = 2; _Variants = std::variant<foo, bar>&; long unsigned int ...__indices = ; std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...), __dimensions ...>, std::tuple<_Variants ...>, std::integer_sequence<long unsigned int, __indices ...> >::_Array_type = std::__detail::__variant::_Multi_array<std::__cxx11::basic_string<char> (*)(visitor&&, std::variant<foo, bar>&), 2> std::index_sequence<__indices ...> = std::integer_sequence<long unsigned int, 0, 1>]'
/usr/local/include/c++/8.1.0/variant:803:19: required from 'static constexpr std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...), __dimensions ...>, std::tuple<_Variants ...>, std::integer_sequence<long unsigned int, __indices ...> >::_Array_type std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...), __dimensions ...>, std::tuple<_Variants ...>, std::integer_sequence<long unsigned int, __indices ...> >::_S_apply() [with _Result_type = std::__cxx11::basic_string<char> _Visitor = visitor&&; long unsigned int ...__dimensions = 2; _Variants = std::variant<foo, bar>&; long unsigned int ...__indices = ; std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...), __dimensions ...>, std::tuple<_Variants ...>, std::integer_sequence<long unsigned int, __indices ...> >::_Array_type = std::__detail::__variant::_Multi_array<std::__cxx11::basic_string<char> (*)(visitor&&, std::variant<foo, bar>&), 2>]'
/usr/local/include/c++/8.1.0/variant:863:38: required from 'static constexpr std::__detail::__variant::__gen_vtable<_Result_type, _Visitor, _Variants>::_Array_type std::__detail::__variant::__gen_vtable<_Result_type, _Visitor, _Variants>::_S_apply() [with _Result_type = std::__cxx11::basic_string<char> _Visitor = visitor&&; _Variants = std::variant<foo, bar>&; std::__detail::__variant::__gen_vtable<_Result_type, _Visitor, _Variants>::_Array_type = std::__detail::__variant::_Multi_array<std::__cxx11::basic_string<char> (*)(visitor&&, std::variant<foo, bar>&), 2>]'
/usr/local/include/c++/8.1.0/variant:866:49: required from 'constexpr const std::__detail::__variant::_Multi_array<std::__cxx11::basic_string<char> (*)(visitor&&, std::variant<foo, bar>&), 2> std::__detail::__variant::__gen_vtable<std::__cxx11::basic_string<char>, visitor&&, std::variant<foo, bar>&>::_S_vtable'
/usr/local/include/c++/8.1.0/variant:866:29: required from 'struct std::__detail::__variant::__gen_vtable<std::__cxx11::basic_string<char>, visitor&&, std::variant<foo, bar>&>'
/usr/local/include/c++/8.1.0/variant:1394:23: required from 'constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = visitor; _Variants = std::variant<foo, bar>&]'
main.cpp:34:38: required from here
/usr/local/include/c++/8.1.0/variant:848:43: error: invalid conversion from 'std::__success_type<double>::type (*)(visitor&&, std::variant<foo, bar>&)' aka 'double (*)(visitor&&, std::variant<foo, bar>&)' to 'std::__cxx11::basic_string<char> (*)(visitor&&, std::variant<foo, bar>&)' [-fpermissive]
return _Array_type&__visit_invoke;
【问题讨论】:
因此您可以将您的示例更改为std::visit(printer, x);
【参考方案1】:
std::visit 要求所有组合的返回类型是相同的类型和值类别:
返回类型是从返回的表达式推导出来的,就像通过 decltype 一样。如果对于所有变体的替代类型的所有组合,上述调用不是相同类型和值类别的有效表达式,则该调用是格式错误的。
参见 C++ 标准草案[variant.visit]p2:
要求:对于每个有效的包 m,e(m) 应该是一个有效的表达式。 所有此类表达式应具有相同的类型和值类别;否则,程序是非良构的。
例如,如果每个结构都有一个 int 成员 x 并且您返回它,那么它将不再是格式错误的 see it live on godbolt。在您的情况下,您可以将访问者更改为简单地打印而不是返回值see it live:
struct visitor
template <class T>
void operator()(const T v)
std::cout<< v.s;
;
【讨论】:
以上是关于无法编译以下代码以访问结构的变体的主要内容,如果未能解决你的问题,请参考以下文章