Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stream std::variant<...,...>

My std::variant contains streamable types:

std::variant<int, std::string> a, b;
a = 1;
b = "hi";
std::cout << a << b << std::endl;

Compiling with g++7 with -std=c++1z returns compilation time errors.

An excerpt:

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;
   ~~~~~~~~~~^~~~

Seemingly a std::variant<int, std::string> is not able to stream. How can I achieve that I can directly stream the variant to an output stream?

Expected output:

1hi
like image 481
Tom Avatar asked Nov 07 '17 22:11

Tom


People also ask

How do I print a variant?

To print a variant, enter its name on the initial screen of the variant maintenance tool, select either Attributes or Values in the sub-objects group box and choose Print. Note that you cannot print the values if you are working in change mode.

What is std :: variant in C++?

(since C++17) The class template std::variant represents a type-safe union. An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value (this state is hard to achieve, see valueless_by_exception).


1 Answers

This streams nested variants too.

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;
}

Use as:

std::cout << streamer{a} << streamer{b} << '\n';
like image 175
T.C. Avatar answered Sep 23 '22 15:09

T.C.