С++ 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;
Кто-нибудь знает, что это возможно?
Ответы
Ответ 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;
}
}