Подтвердить что ты не робот

С++ cout auto separator

Мне интересно, есть ли способ std::cout автоматически вставить некоторое предопределенное значение между печатными последовательностями.

Например:

std::cout << 2 << 3 << 33 << 45 << std::endl;

выходы

233345

и я хотел бы, чтобы он выводил

2 3 33 45

и я знаю, что это легко:

std::cout << 2 << " " << 3 <<  " " << 33 <<  " " << 45 << std::endl;

Но я задаюсь вопросом, есть ли способ автоматизировать это, например:

std::cout << set_some_separator(" ") << 2 << 3 << 33 << 45 << std::endl;

Кто-нибудь знает, что это возможно?

4b9b3361

Ответ 1

Ну, меня избили. Я все равно отправлю его.

Изменить: ну, после прочтения ответа Нима, мой действительно достигает точного синтаксиса, который хотел бы пожелать.

#include <iostream>
#include <algorithm>

struct with_separator {
    with_separator(std::string sep)
    : sep(std::move(sep)) {}

    std::string sep;
};

struct separated_stream {
    separated_stream(std::ostream &stream, std::string sep)
    : _stream(stream), _sep(std::move(sep)), _first(true) {}

    template <class Rhs>
    separated_stream &operator << (Rhs &&rhs) {
        if(_first)
            _first = false;
        else
            _stream << _sep;

        _stream << std::forward<Rhs>(rhs);
        return *this;
    }

    separated_stream &operator << (std::ostream &(*manip)(std::ostream&)) {
        manip(_stream);
        return *this;
    }

    private:
    std::ostream &_stream;
    std::string _sep;
    bool _first;
};

separated_stream operator << (std::ostream &stream, with_separator wsep) {
    return separated_stream(stream, std::move(wsep.sep));
}

int main()
{
    std::cout << with_separator(", ") << 1 << 2 << 3 << std::endl;
}

Выход:

1, 2, 3

Ответ 2

Простой ответ Нет, однако вы можете перевернуть свой собственный...

#include <iostream>
#include <sstream>

using namespace std;

struct set_some_separator{
    set_some_separator(const char* sep) : _sep(sep)
    { };

    template <typename T>
    set_some_separator& operator<<(const T& v)
    {
        _str << v << _sep;
        return *this;
    }

    friend
    ostream& operator<<(ostream& os, const set_some_separator& s)
    { return os << s._str.str(); }

    const char* _sep;
    ostringstream _str;
};

int main()
{
    cout << (set_some_separator(" ") << 2 << 3 << 33 << 45) << endl;
}

Хорошо, формат cout немного отличается, hey-ho...

Ответ 3

Не совсем то же самое, но:

#include <array>
#include <iostream>
#include <iterator>

int main() {
    std::array<int, 3> data = { 1, 2, 3 };
    std::ostream_iterator<int> out(std::cout, " ");
    std::copy(data.begin(), data.end(), out);
    std::cout << '\n';
    return 0;
}

Ответ 4

Простое решение, возможно, вы можете настроить его, чтобы использовать <<

template<typename T> 
void myout(T value) 
{ 
   std::cout << value << std::endl; 
} 

template<typename First, typename ... Rest> 
void myout(First first, Rest ... rest) 
{ 
   std::cout << first << " ";
   myout(rest...); 
}


myout('a',"Hello",1,2,3,22/7.0);

Ответ 5

Как использовать ostream_iterator

int main()
{
     std::vector<int> data {2,3,33,45};
     std::copy(std::begin(data), std::end(data),
               std::ostream_iterator(std::cout, " "));
     std::cout << "\n";
}

Ответ 6

С++ 17-кратное выражение с оператором запятой может создать приятный однострочный:

[](auto &&...xs){ ((std::cout << xs << ',') , ...); }(2,3,33,45);

Ответ 7

Если вы просто ищете способ печати вектора с правильно разделенными его элементами (и без дополнительного разделителя в конце), попробуйте следующее:

#include <iostream>
#include <vector>

int main()
{
  std::vector<int> v{1, 2, 3};

  auto it = v.begin();
  if (it != v.end())
  {
    std::cout << *it;
    ++it;
  }

  for (; it != v.end(); ++it)
  {
    std::cout << ", " << *it;
  }
}