请考虑以下内容:
#include <variant>
#include <iostream>
int main ( )
{
std::variant<int, float> v { 10.f };
std::cout << v.index() << std::endl;
}
这很好用,并输出1
。
现在,假设我们想使用一个甚至不做任何事情的通用输出操作符将变体输出到std::cout
中:
#include <variant>
#include <iostream>
template <typename ... Args>
std::ostream & operator << (std::ostream & os, std::variant<Args...> const & v)
{
return os;
}
int main ( )
{
std::variant<int, float> v { 10.f };
std::cout << v.index() << std::endl;
}
我测试过的所有编译器(gcc-7.1.0,gcc-7.2.0,gcc-7.3.0,gcc-8.1.0,gcc-8.2.0,gcc-8.3.0,gcc-9.1 .0,clang-7,clang-8)也会产生类似的错误,即
/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/variant: In instantiation of ‘constexpr const bool std::__detail::__variant::_Traits<>::_S_default_ctor’:
/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/variant:1219:11: required from ‘class std::variant<>’
a.cpp:14:34: required from here
/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/variant:273:4: error: invalid use of incomplete type ‘struct std::__detail::__variant::_Nth_type<0>’
273 | is_default_constructible_v<typename _Nth_type<0, _Types...>::type>;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/variant:58:12: note: declaration of ‘struct std::__detail::__variant::_Nth_type<0>’
58 | struct _Nth_type;
| ^~~~~~~~~
/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/variant: In instantiation of ‘class std::variant<>’:
a.cpp:14:34: required from here
/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/variant:1238:39: error: static assertion failed: variant must have at least one alternative
1238 | static_assert(sizeof...(_Types) > 0,
| ~~~~~~~~~~~~~~~~~~^~~
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/bits/move.h:55,
from /usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/bits/nested_exception.h:40,
from /usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/exception:144,
from /usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/ios:39,
from /usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/ostream:38,
from /usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/iostream:39,
from a.cpp:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/type_traits: In substitution of ‘template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = (0 != 0); _Tp = void]’:
/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/variant:1301:2: required from ‘class std::variant<>’
a.cpp:14:34: required from here
/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include/g++-v9/type_traits:2426:11: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
2426 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;
| ^~~~~~~~~~~
基本上,它抱怨在std::cout << ...
行实例化一个空变体(类型列表为空)。请注意,我们甚至都不会调用添加的operator <<
。重命名此运算符,或将Args...
显式地设为非空(更改为variant<T, Args...>
)会使错误消失。
正在发生什么,为什么会发生?我是否缺少某些东西,还是(不可能)所有上述编译器的错误?