如何流式传输 std::variant<...,...>
How to stream std::variant<...,...>
我的 std::variant
包含可流类型:
std::variant<int, std::string> a, b;
a = 1;
b = "hi";
std::cout << a << b << std::endl;
使用 g++7 编译时出现 -std=c++1z returns 编译时错误。
节选:
test.cpp: In function 'int main(int, char**)':
test.cpp:10:13: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >')
std::cout << a << b << std::endl;
~~~~~~~~~~^~~~
貌似std::variant<int, std::string>
无法直播。我怎样才能实现我可以直接将变体流式传输到输出流?
预期输出:
1hi
不确定这是个好主意,但我想你可以为 std::variant
.
定义一个 operator<<()
只是为了好玩,我已经实现了您在以下示例中看到的那个(我想可以稍微简化一下)
#include <variant>
#include <iostream>
template <std::size_t I, typename T0, typename ... Ts>
std::enable_if_t<(I == 1U+sizeof...(Ts)), std::ostream &>
streamV (std::ostream & s, std::variant<T0, Ts...> const &)
{ return s; }
template <std::size_t I, typename T0, typename ... Ts>
std::enable_if_t<(I < 1U+sizeof...(Ts)), std::ostream &>
streamV (std::ostream & s, std::variant<T0, Ts...> const & v)
{ return I == v.index() ? s << std::get<I>(v) : streamV<I+1U>(s, v); }
template <typename T0, typename ... Ts>
std::ostream & operator<< (std::ostream & s,
std::variant<T0, Ts...> const & v)
{ return streamV<0U>(s, v); }
int main ()
{
std::variant<int, std::string> a, b;
a = 1;
b = "hi";
std::cout << a << b << std::endl;
}
-- 编辑 --
另一种编写 streamV()
辅助函数的方法,不使用 T0, Ts...
类型,但使用 std::variant_size_v
template <std::size_t I, typename V>
std::enable_if_t<(I == std::variant_size_v<V>), std::ostream &>
streamV (std::ostream & s, V const &)
{ return s; }
template <std::size_t I, typename V>
std::enable_if_t<(I < std::variant_size_v<V>), std::ostream &>
streamV (std::ostream & s, V const & v)
{ return I == v.index() ? s << std::get<I>(v) : streamV<I+1U>(s, v); }
-- 编辑 2 --
正如 T.C 指出的那样。 (谢谢!)我只(使用 streamV()
)实现了 std::visit()
.
的一个效率较低、有趣且用处不大的版本
使用std::visit()
我的例子会变得简单很多
#include <variant>
#include <iostream>
template <typename T0, typename ... Ts>
std::ostream & operator<< (std::ostream & s,
std::variant<T0, Ts...> const & v)
{ std::visit([&](auto && arg){ s << arg;}, v); return s; }
int main ()
{
std::variant<int, std::string> a, b;
a = 1;
b = "hi";
std::cout << a << b << std::endl;
}
我重复一遍:只是为了好玩,因为我认为在标准类型上定义 operator<<()
不是一个好主意。
我建议使用 T.C 中的解决方案。封装变体实例以在特定 class.
中流式传输
这也会流式传输嵌套变体。
template<class T>
struct streamer {
const T& val;
};
template<class T> streamer(T) -> streamer<T>;
template<class T>
std::ostream& operator<<(std::ostream& os, streamer<T> s) {
os << s.val;
return os;
}
template<class... Ts>
std::ostream& operator<<(std::ostream& os, streamer<std::variant<Ts...>> sv) {
std::visit([&os](const auto& v) { os << streamer{v}; }, sv.val);
return os;
}
用作:
std::cout << streamer{a} << streamer{b} << '\n';
注意:以下示例摘自 Igor Tandetnik 对问题本身的评论。
std::visit
是标准库中的一个函数,可用于此目的:
#include <variant>
#include <iostream>
int main() {
std::variant<int, std::string> value = 42;
std::visit([](const auto &elem) { std::cout << elem << '\n'; }, value);
}
上面的代码片段本质上是一种奇特的写作方式:
#include <variant>
#include <iostream>
int main() {
std::variant<int, std::string> value = 42;
if(std::holds_alternative<int>(value)) {
std::cout << std::get<int>(value) << '\n';
} else {
std::cout << std::get<std::string>(value) << '\n';
}
}
我的 std::variant
包含可流类型:
std::variant<int, std::string> a, b;
a = 1;
b = "hi";
std::cout << a << b << std::endl;
使用 g++7 编译时出现 -std=c++1z returns 编译时错误。
节选:
test.cpp: In function 'int main(int, char**)':
test.cpp:10:13: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >')
std::cout << a << b << std::endl;
~~~~~~~~~~^~~~
貌似std::variant<int, std::string>
无法直播。我怎样才能实现我可以直接将变体流式传输到输出流?
预期输出:
1hi
不确定这是个好主意,但我想你可以为 std::variant
.
operator<<()
只是为了好玩,我已经实现了您在以下示例中看到的那个(我想可以稍微简化一下)
#include <variant>
#include <iostream>
template <std::size_t I, typename T0, typename ... Ts>
std::enable_if_t<(I == 1U+sizeof...(Ts)), std::ostream &>
streamV (std::ostream & s, std::variant<T0, Ts...> const &)
{ return s; }
template <std::size_t I, typename T0, typename ... Ts>
std::enable_if_t<(I < 1U+sizeof...(Ts)), std::ostream &>
streamV (std::ostream & s, std::variant<T0, Ts...> const & v)
{ return I == v.index() ? s << std::get<I>(v) : streamV<I+1U>(s, v); }
template <typename T0, typename ... Ts>
std::ostream & operator<< (std::ostream & s,
std::variant<T0, Ts...> const & v)
{ return streamV<0U>(s, v); }
int main ()
{
std::variant<int, std::string> a, b;
a = 1;
b = "hi";
std::cout << a << b << std::endl;
}
-- 编辑 --
另一种编写 streamV()
辅助函数的方法,不使用 T0, Ts...
类型,但使用 std::variant_size_v
template <std::size_t I, typename V>
std::enable_if_t<(I == std::variant_size_v<V>), std::ostream &>
streamV (std::ostream & s, V const &)
{ return s; }
template <std::size_t I, typename V>
std::enable_if_t<(I < std::variant_size_v<V>), std::ostream &>
streamV (std::ostream & s, V const & v)
{ return I == v.index() ? s << std::get<I>(v) : streamV<I+1U>(s, v); }
-- 编辑 2 --
正如 T.C 指出的那样。 (谢谢!)我只(使用 streamV()
)实现了 std::visit()
.
使用std::visit()
我的例子会变得简单很多
#include <variant>
#include <iostream>
template <typename T0, typename ... Ts>
std::ostream & operator<< (std::ostream & s,
std::variant<T0, Ts...> const & v)
{ std::visit([&](auto && arg){ s << arg;}, v); return s; }
int main ()
{
std::variant<int, std::string> a, b;
a = 1;
b = "hi";
std::cout << a << b << std::endl;
}
我重复一遍:只是为了好玩,因为我认为在标准类型上定义 operator<<()
不是一个好主意。
我建议使用 T.C 中的解决方案。封装变体实例以在特定 class.
中流式传输这也会流式传输嵌套变体。
template<class T>
struct streamer {
const T& val;
};
template<class T> streamer(T) -> streamer<T>;
template<class T>
std::ostream& operator<<(std::ostream& os, streamer<T> s) {
os << s.val;
return os;
}
template<class... Ts>
std::ostream& operator<<(std::ostream& os, streamer<std::variant<Ts...>> sv) {
std::visit([&os](const auto& v) { os << streamer{v}; }, sv.val);
return os;
}
用作:
std::cout << streamer{a} << streamer{b} << '\n';
注意:以下示例摘自 Igor Tandetnik 对问题本身的评论。
std::visit
是标准库中的一个函数,可用于此目的:
#include <variant>
#include <iostream>
int main() {
std::variant<int, std::string> value = 42;
std::visit([](const auto &elem) { std::cout << elem << '\n'; }, value);
}
上面的代码片段本质上是一种奇特的写作方式:
#include <variant>
#include <iostream>
int main() {
std::variant<int, std::string> value = 42;
if(std::holds_alternative<int>(value)) {
std::cout << std::get<int>(value) << '\n';
} else {
std::cout << std::get<std::string>(value) << '\n';
}
}