gpt4 book ai didi

c++ - 无法使用 std::variant 的重载运算符 <<() 流式传输 std::endl

转载 作者:太空宇宙 更新时间:2023-11-04 12:34:56 24 4
gpt4 key购买 nike

This answer 描述了如何流式传输独立的 std::variant。但是,当 std::variant 存储在 std::unordered_map 中时,它似乎不起作用。

以下 example :

#include <iostream>
#include <string>
#include <variant>
#include <complex>
#include <unordered_map>

// https://stackoverflow.com/a/46893057/8414561
template<typename... Ts>
std::ostream& operator<<(std::ostream& os, const std::variant<Ts...>& v)
{
std::visit([&os](auto&& arg) {
os << arg;
}, v);
return os;
}

int main()
{
using namespace std::complex_literals;
std::unordered_map<int, std::variant<int, std::string, double, std::complex<double>>> map{
{0, 4},
{1, "hello"},
{2, 3.14},
{3, 2. + 3i}
};

for (const auto& [key, value] : map)
std::cout << key << "=" << value << std::endl;
}

编译失败:

In file included from main.cpp:3:
/usr/local/include/c++/8.1.0/variant: In instantiation of 'constexpr const bool std::__detail::__variant::_Traits<>::_S_default_ctor':
/usr/local/include/c++/8.1.0/variant:1038:11: required from 'class std::variant<>'
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:300:4: error: invalid use of incomplete type 'struct std::__detail::__variant::_Nth_type<0>'
is_default_constructible_v<typename _Nth_type<0, _Types...>::type>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/c++/8.1.0/variant:58:12: note: declaration of 'struct std::__detail::__variant::_Nth_type<0>'
struct _Nth_type;
^~~~~~~~~
/usr/local/include/c++/8.1.0/variant: In instantiation of 'class std::variant<>':
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:1051:39: error: static assertion failed: variant must have at least one alternative
static_assert(sizeof...(_Types) > 0,
~~~~~~~~~~~~~~~~~~^~~

为什么会这样?怎么可能修复它?

最佳答案

[temp.arg.explicit]/3 ,我们有这个惊人的句子:

A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments.

这是什么意思?什么是尾随模板参数包?没有其他推论是什么意思?这些都是没有真正答案的好问题。但这会产生非常有趣的后果。考虑:

template <typename... Ts> void f(std::tuple<Ts...>);
f({}); // ok??

这是...格式正确的。我们无法推断Ts...所以我们推断它是空的。这给我们留下了 std::tuple<> ,这是一个完全有效的类型 - 并且是一个完全有效的类型,甚至可以用 {} 实例化。 .所以这个编译!

那么当我们从空参数包中推导出的东西不是有效类型时会发生什么?这是 an example :

template <class... Ts>
struct Y
{
static_assert(sizeof...(Ts)>0, "!");
};


template <class... Ts>
std::ostream& operator<<(std::ostream& os, Y<Ts...> const& )
{
return os << std::endl;
}

operator<<是一个潜在的候选人,但推论失败了……或者看起来是这样。直到我们想出 Ts...作为空。但是Y<>是无效类型!我们甚至不去尝试发现我们无法构造一个 Y<>。来自 std::endl - 我们已经失败了

这与 variant 的情况基本相同,因为 variant<>不是有效类型。

简单的解决方法是简单地更改您的函数模板,使其不再采用 variant<Ts...>。到 variant<T, Ts...> .这不能再推导出variant<> ,这根本不可能,所以我们没有问题。

关于c++ - 无法使用 std::variant 的重载运算符 <<() 流式传输 std::endl,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56845299/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com