使用C++时如何改善编译器错误消息。 std ::访问?
我正在使用C ++ 17的std ::访问()
在带有许多替代方案的变体上函数,并且每当我忘记访问者中的一个或多个替代方案时,编译器产生的错误消息非常难以理解。
例如
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
);
,在上面的代码示例中,编译器可以根据替代数量产生数千个字符的错误消息。有没有办法改进这些错误消息,以便编译器会输出以下内容?
example.cc:8-13: error: Non-exhaustive visitor -- missing alternative of type 'X'
I am using C++17's std::visit()
function on a variant with many alternatives, and the error messages produced by the compiler whenever I forget one or more of the alternatives in my visitor are quite difficult to understand.
e.g.
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
);
In the above code example, the compiler can produce error messages that are thousands of characters in length, depending on the number of alternatives. Is there a way to improve these error messages so that the compiler will output something like the following instead?
example.cc:8-13: error: Non-exhaustive visitor -- missing alternative of type 'X'
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我第一次尝试解决此问题的尝试在这里。经过一些谷歌搜索和大量的反复试验之后,我想出了一个更好的解决方案,我发布了在这里。为了方便起见,我将在下面复制解决方案。
这是概念证明。
如您所见,
访问者
类模板接受std :: variant
将作为模板参数键入,从中定义了必须在任何子类中实现的接口从模板类实例化继承。如果在儿童课程中,您碰巧忘记覆盖一种纯虚拟方法,那么您将获得以下错误。这比编译器使用
std ::访问()
时通常生成的错误消息要容易得多。My first attempt at solving this problem can be found here. After some some googling and lots of trial and error, I've come up with a much better solution, which I've posted here. I'll copy-paste the solution, below, for convenience.
Here is a proof of concept.
As you can see, the
Visitor
class template accepts astd::variant
type as a template parameter, from which it will define an interface that must be implemented in any child classes that inherit from the template class instantiation. If, in a child class, you happen to forget to override one of the pure virtual methods, you will get an error like the following.This is much easier to understand than the error messages that the compiler usually generates when using
std::visit()
.IMO您可以将过载设置包装在函数对象中,该功能对象在错过的情况下执行默认例程(就像
default
e节 switch> switch> switch 语句)一样。而且我将默认的过载放在开始时,以免忘记它:std :: bind_back
不是奇迹。它只是提供清洁的语法,而无需占位座参数:IMO you can wrap the overload set in a function object that executes a default routine on missed cases (much like a
default
section in aswitch
statement). And I put the default overload at the beginning, so as to not forget it:The
std::bind_back
is not a miracle. It just provides cleaner syntax with no need for place holder parameters:如果您可以使用C ++ 20,则可以使用概念。 AFAIK,改进模板代码中的错误消息是人们想要拥有此功能的关键原因之一。 “简单地”包裹
std ::访问
使用您自己的访问功能访问 <代码>需要子句:使用此包装器将Clang的错误消息从184行减少到28行。 live demo
(请注意,此实现仅涵盖
const std :: variant&lt; ...&gt;&amp;
一次,而其中只有一个,而std ::访问
可以处理 不幸的是,它一次任意数量的变体。它仍然不如您在问题中表达的愿望那么短,但它比原始的要好。
旁注:我不能告诉你,为什么C ++ 20's
std ::访问
没有此内置的子句。If you can use C++20, you can make use of concepts. Afaik, improving error messages in templated code was one of the key reasons why people wanted to have this feature. "Simply" wrap
std::visit
with your own visit function and add arequires
clause:Using this wrapper reduces clang's error message from 184 lines down to 28 lines. Live Demo
(Note that this implementation only covers
const std::variant<...>&
and only one of them at a time, whilestd::visit
can handle an arbitrary number of variants at once.)Unfortunately, it is still not as short and descriptive as the wish you expressed in your question, but it is mush better than the original, I guess.
Side note: I cannot tell you, why C++20's
std::visit
doesn't have thisrequires
clause built in.我想出了一个不那么理想的解决方案,但总比没有好。如果最终出现了更好的解决方案,我将很乐意将接受的答案切换为此。
这是概念证明。
用
-fmax-errors = 1
(gcc)或-ferror-limit = 1
(clang)时,std_visit_improve_compiler_errors_errors_errors_erors_lambda
导致静态sattic Assertert,消息要打印出来,解释错误。但是,不幸的是,它并没有告诉我们哪种选择不满意,并且仍然不能阻止原始的,漫长的且实际上毫无智能的编译器错误被生成。但是,至少,错误的原因更为明显。例如
I've come up with a less-than-ideal solution, but it's better than nothing. If a better solution eventually comes along, I will happily switch the accepted answer to that.
Here's a proof of concept.
When compiling with
-fmax-errors=1
(GCC) or-ferror-limit=1
(Clang), theSTD_VISIT_IMPROVE_COMPILER_ERRORS_LAMBDA
causes the static assert message to print out, explaining the error. Unfortunately, however, it does not tell us which alternative is unsatisfied and it still does not prevent the original, long and practically-unintelligible compiler error from being generated. At least, though, the cause of the error is more clear.e.g.