jin*_*123 10 c++ compiler-errors std-variant
我在具有std::visit()
许多替代方案的变体上使用 C++17 的函数,每当我忘记访问者中的一个或多个替代方案时,编译器生成的错误消息都非常难以理解。
例如
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
using Foo = std::variant<A, B, /* ... many more alternatives ... */>;
Foo foo;
std::visit(overloaded{
[](A const& a) { /* ... */ },
[](B const& b) { /* ... */ },
/* ... forgot 1+ alternatives ... */
}, foo
);
Run Code Online (Sandbox Code Playgroud)
在上面的代码示例中,编译器可以生成长度为数千个字符的错误消息,具体取决于替代方案的数量。有没有办法改进这些错误消息,以便编译器输出类似以下内容?
example.cc:8-13: error: Non-exhaustive visitor -- missing alternative of type 'X'
Run Code Online (Sandbox Code Playgroud)
我第一次尝试解决这个问题可以在这里找到。经过一些谷歌搜索和大量的试验和错误后,我想出了一个更好的解决方案,我已将其发布在这里。为了方便起见,我将在下面复制粘贴解决方案。
\n这是一个概念证明。
\n#include <iostream>\n#include <variant>\n\n\ntemplate <typename> class Test { };\n\nusing Foo = std::variant<\n Test<struct A>,\n Test<struct B>,\n Test<struct C>,\n Test<struct D>\n >;\n\nusing Bar = std::variant<\n Test<struct E>,\n Test<struct F>,\n Test<struct G>,\n Test<struct H>,\n Test<struct I>,\n Test<struct J>,\n Test<struct K>,\n Test<struct L>\n >;\n\n\ntemplate <typename T>\nstruct DefineVirtualFunctor\n{\n virtual int operator()(T const&) const = 0;\n};\n\ntemplate <template <typename> typename Modifier, typename... Rest>\nstruct ForEach { };\ntemplate <template <typename> typename Modifier, typename T, typename... Rest>\nstruct ForEach<Modifier, T, Rest...> : Modifier<T>, ForEach<Modifier, Rest...> { };\n\ntemplate <typename Variant>\nstruct Visitor;\ntemplate <typename... Alts>\nstruct Visitor<std::variant<Alts...>> : ForEach<DefineVirtualFunctor, Alts...> { };\n\n\nstruct FooVisitor final : Visitor<Foo>\n{\n int operator()(Test<A> const&) const override { return 0; }\n int operator()(Test<B> const&) const override { return 1; }\n int operator()(Test<C> const&) const override { return 2; }\n int operator()(Test<D> const&) const override { return 3; }\n};\n\nstruct BarVisitor final : Visitor<Bar>\n{\n int operator()(Test<E> const&) const override { return 4; }\n int operator()(Test<F> const&) const override { return 5; }\n int operator()(Test<G> const&) const override { return 6; }\n int operator()(Test<H> const&) const override { return 7; }\n int operator()(Test<I> const&) const override { return 8; }\n int operator()(Test<J> const&) const override { return 9; }\n int operator()(Test<K> const&) const override { return 10; }\n int operator()(Test<L> const&) const override { return 11; }\n};\n\n\nint main(int argc, char const* argv[])\n{\n Foo foo;\n Bar bar;\n \n switch (argc) {\n case 0: foo = Foo{ std::in_place_index<0> }; break;\n case 1: foo = Foo{ std::in_place_index<1> }; break;\n case 2: foo = Foo{ std::in_place_index<2> }; break;\n default: foo = Foo{ std::in_place_index<3> }; break;\n }\n switch (argc) {\n case 0: bar = Bar{ std::in_place_index<0> }; break;\n case 1: bar = Bar{ std::in_place_index<1> }; break;\n case 2: bar = Bar{ std::in_place_index<2> }; break;\n case 3: bar = Bar{ std::in_place_index<3> }; break;\n case 4: bar = Bar{ std::in_place_index<4> }; break;\n case 5: bar = Bar{ std::in_place_index<5> }; break;\n case 6: bar = Bar{ std::in_place_index<6> }; break;\n default: bar = Bar{ std::in_place_index<7> }; break;\n }\n \n std::cout << std::visit(FooVisitor{ }, foo) << "\\n";\n std::cout << std::visit(BarVisitor{ }, bar) << "\\n";\n\n return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n正如您所看到的,Visitor
类模板接受一个std::variant
类型作为模板参数,它将定义一个接口,该接口必须在从模板类实例化继承的任何子类中实现。如果在子类中,您碰巧忘记重写纯虚方法之一,您将收到如下错误。
$ g++ -std=c++17 -o example example.cc\nexample.cc: In function \xe2\x80\x98int main(int, const char**)\xe2\x80\x99:\nexample.cc:87:41: error: invalid cast to abstract class type \xe2\x80\x98BarVisitor\xe2\x80\x99\n 87 | std::cout << std::visit(BarVisitor{ }, bar) << "\\n";\n | ^\nexample.cc:51:8: note: because the following virtual functions are pure within \xe2\x80\x98BarVisitor\xe2\x80\x99:\n 51 | struct BarVisitor final : Visitor<Bar>\n | ^~~~~~~~~~\nexample.cc:29:17: note: \xe2\x80\x98int DefineVirtualFunctor<T>::operator()(const T&) const [with T = Test<J>]\xe2\x80\x99\n 29 | virtual int operator()(T const&) const = 0;\n | ^~~~~~~~\n
Run Code Online (Sandbox Code Playgroud)\n这比编译器在使用时通常生成的错误消息更容易理解std::visit()
。