10

I’d like to write operator<< for std::variant. The assumption will be that the operator<< for a particular variant will only be valid if operator<< is valid for all the types that the variant can contain.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Robert Fisher
  • 578
  • 4
  • 20

1 Answers1

14
//g++ (GCC) 7.2.0
//g++ -std=c++1z -O2 -Wall -pedantic -pthread main.cpp
#include <iostream>
#include <string>
#include <variant>
#include <complex>

template<typename T, typename... Ts>
std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)
{
    std::visit([&os](auto&& arg) {
        os << arg;
    }, v);
    return os;
}

int main()
{
    using namespace std::complex_literals;
    std::variant<int, std::string, double, std::complex<double>> v = 4;
    std::cout << v << '\n';
    v = "hello";
    std::cout << v << '\n';
    v = 3.14;
    std::cout << v << '\n';
    v = 2. + 3i;
    std::cout << v << '\n';
}

Demo

This relies on passing a generic lambda to std::visit.

See this question for a problem with the previous version of this answer. This answer has been updated to avoid that problem.

Robert Fisher
  • 578
  • 4
  • 20
  • 4
    Can't you just use `template std::ostream& operator<<(std::ostream& os, const std::variant& v)`? – Caleth Oct 23 '17 at 15:35
  • @Caleth, actually no. He can't, because of https://stackoverflow.com/q/52845621/225186 . The sfinae version was correct. – alfC Oct 17 '18 at 02:11
  • @alfC just adding a typename in front of the pack will suffice `template` – Caleth Oct 17 '18 at 08:21
  • So, the possible fixes are: (1) Restore the SFINAE. (2) Change `variant` to `variant`. (3) Add `typename`. (4) Call it a compiler bug and change nothing. I'm tempted to go with 3, but I'm kind of feeling like it should first be added as an answer to [the new question](https://stackoverflow.com/q/52845621/225186) and discussed with the other solutions there. – Robert Fisher Oct 17 '18 at 12:55
  • @RobertFisher, what is (3)? (4) It is not a compiler bug. – alfC Oct 17 '18 at 15:17
  • @alfC Hmm...regarding (3), maybe I was confused about Caleth's comment about "adding a typename...will suffice". (I wish comments could be threaded, even if we don't want it to become chat.) Regarding (4), I now see that Barry described it as a “language bug” instead of a compiler bug. I misread that. So, I guess (2) is the best choice? – Robert Fisher Oct 17 '18 at 15:26
  • @Caleth, Yes, that would also work, it is what I proposed in my answer https://stackoverflow.com/a/52846061/225186 – alfC Oct 17 '18 at 15:28
  • @RobertFisher It would be helpful to make the code you supplied work, it is different to the code in the "Demo" link and doesn't compile. – Jesse Pepper May 20 '20 at 07:12