我想出了一个不太理想的解决方案,但总比没有好。如果最终有更好的解决方案出现,我会很乐意将采纳答案切换到那个更好的方案。
这是一个概念验证。
#include <variant>
#define STD_VISIT_IMPROVE_COMPILER_ERRORS_LAMBDA \
[](auto... __args) { \
static_assert(always_false_v<decltype(__args)...>, "non-exhaustive visitor"); \
},
template <typename... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template <typename... Ts> overloaded(Ts...) -> overloaded<Ts...>;
template <typename> constexpr bool always_false_v = false;
template <typename> class Test { };
using Foo = std::variant<
std::monostate,
Test<struct A>,
Test<struct B>,
Test<struct C>,
Test<struct D>,
Test<struct E>,
Test<struct F>,
Test<struct G>,
Test<struct H>,
Test<struct I>,
Test<struct J>,
Test<struct K>,
Test<struct L>,
Test<struct M>,
Test<struct N>,
Test<struct O>,
Test<struct P>,
Test<struct Q>,
Test<struct R>,
Test<struct S>,
Test<struct T>,
Test<struct U>,
Test<struct V>,
Test<struct W>,
Test<struct X>,
Test<struct Y>,
Test<struct Z>
>;
int main(int argc, char const* argv[])
{
Foo foo;
switch (argc) {
case 0: foo = Foo{ std::in_place_index< 0> }; break;
case 1: foo = Foo{ std::in_place_index< 1> }; break;
case 2: foo = Foo{ std::in_place_index< 2> }; break;
case 3: foo = Foo{ std::in_place_index< 3> }; break;
case 4: foo = Foo{ std::in_place_index< 4> }; break;
case 5: foo = Foo{ std::in_place_index< 5> }; break;
case 6: foo = Foo{ std::in_place_index< 6> }; break;
case 7: foo = Foo{ std::in_place_index< 7> }; break;
case 8: foo = Foo{ std::in_place_index< 8> }; break;
case 9: foo = Foo{ std::in_place_index< 9> }; break;
case 10: foo = Foo{ std::in_place_index<10> }; break;
case 11: foo = Foo{ std::in_place_index<11> }; break;
case 12: foo = Foo{ std::in_place_index<12> }; break;
case 13: foo = Foo{ std::in_place_index<13> }; break;
case 14: foo = Foo{ std::in_place_index<14> }; break;
case 15: foo = Foo{ std::in_place_index<15> }; break;
case 16: foo = Foo{ std::in_place_index<16> }; break;
case 17: foo = Foo{ std::in_place_index<17> }; break;
case 18: foo = Foo{ std::in_place_index<18> }; break;
case 19: foo = Foo{ std::in_place_index<19> }; break;
case 20: foo = Foo{ std::in_place_index<20> }; break;
case 21: foo = Foo{ std::in_place_index<21> }; break;
case 22: foo = Foo{ std::in_place_index<22> }; break;
case 23: foo = Foo{ std::in_place_index<23> }; break;
case 24: foo = Foo{ std::in_place_index<24> }; break;
case 25: foo = Foo{ std::in_place_index<25> }; break;
default: foo = Foo{ std::in_place_index<26> }; break;
}
return std::visit(overloaded{
[](std::monostate) { return 0; },
[](Test<A> const&) { return 1; },
[](Test<B> const&) { return 2; },
[](Test<C> const&) { return 3; },
[](Test<D> const&) { return 4; },
[](Test<E> const&) { return 5; },
[](Test<F> const&) { return 6; },
[](Test<G> const&) { return 7; },
[](Test<H> const&) { return 8; },
[](Test<I> const&) { return 9; },
[](Test<J> const&) { return 10; },
[](Test<K> const&) { return 11; },
[](Test<L> const&) { return 12; },
[](Test<M> const&) { return 13; },
[](Test<N> const&) { return 14; },
[](Test<O> const&) { return 15; },
[](Test<P> const&) { return 16; },
[](Test<Q> const&) { return 17; },
[](Test<R> const&) { return 18; },
[](Test<S> const&) { return 19; },
[](Test<T> const&) { return 20; },
[](Test<U> const&) { return 21; },
[](Test<V> const&) { return 22; },
[](Test<W> const&) { return 23; },
[](Test<Y> const&) { return 25; },
[](Test<Z> const&) { return 26; },
STD_VISIT_IMPROVE_COMPILER_ERRORS_LAMBDA
}, foo
);
}
当使用-fmax-errors=1
(GCC)或-ferror-limit=1
(Clang)进行编译时,STD_VISIT_IMPROVE_COMPILER_ERRORS_LAMBDA
会导致静态断言消息打印出来,解释错误。然而,它并没有告诉我们哪个替代方案不满足要求,并且仍然无法防止原始、冗长和几乎难以理解的编译器错误被生成。至少,错误的原因更加清晰。
例如:
$ g++ -std=c++17 -fmax-errors=1 -o example example.cc
...
example.cc:5:19: error: static assertion failed: non-exhaustive visitor
5 | static_assert(always_false_v<decltype(__args)...>, "non-exhaustive visitor")
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
example.cc:107:9: note: in expansion of macro ‘STD_VISIT_IMPROVE_COMPILER_ERRORS_LAMBDA’
107 | STD_VISIT_IMPROVE_COMPILER_ERRORS_LAMBDA
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated due to -fmax-errors=1.
visit
封装器,否则无法解决这个问题。但是尽管错误很可怕,但可能的原因并不太多:要么是缺少备选项,要么是返回类型不匹配。 - HolyBlackCatg++
、clang++
和MSVC
。其中一个希望会给出一个可理解的错误信息 :-) - Ted Lyngmostd::visit()
? - jinscoe123