1

Is it possible to pass to a debug streaming operator a list of heterogeneous types that are streamable?

string str("blabla");
std::cout << {"A", 3,  str} << std::endl;

I guess it could be possible with something like a variadic template? I want the operator << to call each of the elements in the list and append a comma.

Llopeth
  • 406
  • 5
  • 11

1 Answers1

3

You can't use initializer list for heterogeneous types, but std::tuple is ok.

Make sure there is no unnecessary copy made. Here is a solution using C++17.

#include <tuple>
#include <string>
#include <iostream>

template<class... Ts>
std::ostream&
operator<<(std::ostream &os, std::tuple<Ts...> &&tp)
{
    auto lam = [&] (auto &&arg0, auto&& ...args) -> auto&& {
        os << arg0;
        ([&] (auto&& arg) {
            os << ", " << arg;
        } (args), ...);
        return os;
    };

    return std::apply(lam, std::move(tp));
}

int main() {
    std::string str("blabla");
    std::cout << std::forward_as_tuple("A", 3,  str) << std::endl;
}
llllllllll
  • 16,169
  • 4
  • 31
  • 54
  • and this does not make a copy of `str` (but takes a `const &`)? – Walter Oct 16 '18 at 11:03
  • What about using a fold expression? – Walter Oct 16 '18 at 11:04
  • @Walter No copy for any case, everything is forwarded. fold isn't applicable, there is an additional `", " – llllllllll Oct 16 '18 at 11:27
  • it should be possible to code this as fold -- though I don't have much experience with this. – Walter Oct 17 '18 at 10:19
  • @Walter Not sure which 'fold' you're referring to. My code is actually fold around comma operator, which could be simplified as `((os << ", " << args), ...)`. But I kinda prefer a lambda anyway... If you're talking about the fold around `<<`, I don't think it's possible. – llllllllll Oct 18 '18 at 08:38