打印逗号与std :: vector分开的列表
Print comma separated list from std::vector
我正在尝试从 std::vector<MyClass>
打印单个细节的逗号分隔列表。到目前为止,我看到的最简单,最聪明的方法是使用
std::ostringstream ss;
std::copy(vec.begin(), vec.end() - 1, std::ostream_iterator<std::string>(ss, ", "))
ss << vec.back();
当我打印一个字符串向量时,
效果很好。但是,现在我试图打印有关MyClass
的单个细节。我知道我可以做
(x.specific_detail for x in vec)
要获得我感兴趣的东西的发电机表达式。我想知道我是否可以在这里做类似的事情,或者是否卡住了
for (auto it = vec.begin(); it != vec.end(); ++it) {
// Do stuff here
}
解决此问题的一种方法是:
std::string separator;
for (auto x : vec) {
ss << separator << x.specific_detail;
separator = ",";
}
一种相当简单且可重复使用的方法:
#include <vector>
#include <iostream>
template<class Stream, class T, class A>
Stream& printem(Stream&os, std::vector<T, A> const& v)
{
auto emit = [&os, need_comma = false](T const& x) mutable
{
if (need_comma) os << ", ";
os << x;
need_comma = true;
};
for(T const& x : v) emit(x);
return os;
}
int main()
{
auto v = std::vector<int> { 1, 2, 3, 4 , 5 };
printem(std::cout, v) << std::endl;
}
和另一种定义用于打印容器的可扩展协议的方式:
#include <vector>
#include <iostream>
template<class Container>
struct container_printer;
// specialise for a class of container
template<class T, class A>
struct container_printer<std::vector<T, A>>
{
using container_type = std::vector<T, A>;
container_printer(container_type const& c) : c(c) {}
std::ostream& operator()(std::ostream& os) const
{
const char* sep = "";
for (const T& x : c) {
os << sep << x;
sep = ", ";
}
return os;
}
friend std::ostream& operator<<(std::ostream& os, container_printer const& cp)
{
return cp(os);
}
container_type c;
};
template<class Container>
auto print_container(Container&& c)
{
using container_type = typename std::decay<Container>::type;
return container_printer<container_type>(c);
}
int main()
{
auto v = std::vector<int> { 1, 2, 3, 4 , 5 };
std::cout << print_container(v) << std::endl;
}
...当然我们可以走得更远...
#include <vector>
#include <iostream>
template<class...Stuff>
struct container_printer;
// specialise for a class of container
template<class T, class A, class Separator, class Gap, class Prefix, class Postfix>
struct container_printer<std::vector<T, A>, Separator, Gap, Prefix, Postfix>
{
using container_type = std::vector<T, A>;
container_printer(container_type const& c, Separator sep, Gap gap, Prefix prefix, Postfix postfix)
: c(c)
, separator(sep)
, gap(gap)
, prefix(prefix)
, postfix(postfix) {}
std::ostream& operator()(std::ostream& os) const
{
Separator sep = gap;
os << prefix;
for (const T& x : c) {
os << sep << x;
sep = separator;
}
return os << gap << postfix;
}
friend std::ostream& operator<<(std::ostream& os, container_printer const& cp)
{
return cp(os);
}
container_type c;
Separator separator;
Gap gap;
Prefix prefix;
Postfix postfix;
};
template<class Container, class Sep = char, class Gap = Sep, class Prefix = char, class Postfix = char>
auto print_container(Container&& c, Sep sep = ',', Gap gap = ' ', Prefix prefix = '[', Postfix postfix = ']')
{
using container_type = typename std::decay<Container>::type;
return container_printer<container_type, Sep, Gap, Prefix, Postfix>(c, sep, gap, prefix, postfix);
}
int main()
{
auto v = std::vector<int> { 1, 2, 3, 4 , 5 };
// json-style
std::cout << print_container(v) << std::endl;
// custom
std::cout << print_container(v, " : ", " ", "(", ")") << std::endl;
// custom
std::cout << print_container(v, "-", "", ">>>", "<<<") << std::endl;
}
预期输出:
[ 1,2,3,4,5 ]
( 1 : 2 : 3 : 4 : 5 )
>>>1-2-3-4-5<<<
这是使用std::transform
:
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<std::string> strs = {"Testing", "One", "Two", "Three"};
if (!strs.empty())
{
std::copy(std::begin(strs), std::prev(std::end(strs)), std::ostream_iterator<std::string>(std::cout, ", "));
std::cout << strs.back();
}
std::cout << 'n';
if (!strs.empty())
{
std::transform(std::begin(strs), std::prev(std::end(strs)), std::ostream_iterator<size_t>(std::cout, ", "),
[](const std::string& str) { return str.size(); });
std::cout << strs.back().size();
}
std::cout << 'n';
}
输出:
Testing, One, Two, Three
7, 3, 3, 5
这是一个很小的简单范围库:
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return begin()==end(); }
std::size_t size() const { return std::distance( begin(), end() ); }
range_t without_front( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {std::next(b, n), e};
}
range_t without_back( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {b, std::prev(e, n)};
}
range_t only_front( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {b, std::next(b, n)};
}
range_t only_back( std::size_t n = 1 ) const {
n = (std::min)(size(), n);
return {std::prev(end(), n), end()};
}
};
template<class It>
range_t<It> range(It s, It f) { return {s,f}; }
template<class C>
auto range(C&& c) {
using std::begin; using std::end;
return range( begin(c), end(c) );
}
现在我们准备好了。
auto r = range(vec);
for (auto& front: r.only_front()) {
std::cout << front.x;
}
for (auto& rest: r.without_front()) {
std::cout << "," << rest.x;
}
现场示例。
现在您可以变得更加豪华。增强转换迭代器以及Boost范围,让您可以做类似于Python列表理解的事情。或c 2a。
的rangesv3库编写转换输入迭代器并不难,它只是一堆样板。只需查看输入迭代器的公理,编写一种存储任意迭代器并将大多数方法转发到它的类型。
它还存储一些功能。在*
和->
上,调用Derected Iterator上的功能。
template<class It, class F>
struct transform_iterator_t {
using reference=std::result_of_t<F const&(typename std::iterator_traits<It>::reference)>;
using value_type=reference;
using difference_type=std::ptrdiff_t;
using pointer=value_type*;
using iterator_category=std::input_iterator_tag;
using self=transform_iterator_t;
It it;
F f;
friend bool operator!=( self const& lhs, self const& rhs ) {
return lhs.it != rhs.it;
}
friend bool operator==( self const& lhs, self const& rhs ) {
return !(lhs!=rhs);
}
self& operator++() {
++it;
return *this;
}
self operator++(int) {
auto r = *this;
++*this;
return r;
}
reference operator*() const {
return f(*it);
}
pointer operator->() const {
// dangerous
return std::addressof( **this );
}
};
template<class F>
auto iterator_transformer( F&& f ) {
return [f=std::forward<F>(f)](auto it){
return transform_iterator_t<decltype(it), std::decay_t<decltype(f)>>{
std::move(it), f
};
};
}
template<class F>
auto range_transfromer( F&& f ) {
auto t = iterator_transformer(std::forward<F>(f));
return [t=std::move(t)](auto&&...args){
auto tmp = range( decltype(args)(args)... );
return range( t(tmp.begin()), t(tmp.end()) );
};
}
变压器的实时示例。
,如果我们添加--
,我们甚至可以使用Ostream Iterator。
请注意,std::prev
需要双向迭代器,该迭代器需要向前迭代概念,该迭代概念要求转换器返回实际参考,这是痛苦。
您可以使用已经拥有的确切代码,只需将您传递给std::ostream_iterator
的类型更改为限制其输出:
class MyClassDetail {
const MyClass &m_cls;
public:
MyClassDetail(const MyClass &src) : m_cls(src) {}
friend std::ostream& operator<<(std::ostream &out, const MyClassDetail &in) {
return out << in.m_cls.specific_detail;
}
};
std::copy(vec.begin(), vec.end()-1, std::ostream_iterator<MyClassDetail>(ss, ", "));
ss << MyClassDetail(vec.back());
实时演示
这是最终使用的
// assume std::vector<MyClass> vec
std::ostringstream ss;
std::for_each(vec.begin(), vec.end() - 1,
[&ss] (MyClass &item) {
ss << item.specific_detail << ", ";
}
);
ss << vec.back().specific_detail;
您可以简单地使用完全相同的代码,但定义了操作员&lt;&lt;超载:
ostream &operator<<(ostream& out)
{
out << m_detail;
}
相关文章:
- std::vector 没有重载函数的实例与参数列表匹配
- 使用大括号初始化 std::vector 使用初始值设定项列表
- 替代在python中制作邻接列表与图形问题的字典?(如 C++ 中的 vector<vector<int&g
- 我可以列表初始化 std::vector 并完美转发元素吗?
- 如何在构造函数初始值设定项列表中使用 n 个元素初始化 std::vector<std::time_t>
- 从 std::vector<double> 到 Python 列表的转换失败(提升 python)
- 我可以从实例列表中初始化 std::vector<T*> 吗?
- 尝试使用初始值设定项列表构造"std::vector"的问题
- 错误 C2440:"正在初始化":无法从"初始值设定项列表"转换为"std::vector<char *,std::分配器<_Ty>>
- std::仅移动类型列表:不能在 VC++ 中放入 std::vector
- 消除 std::vector<std::string 的列表初始化的歧义>
- 如何修复邻接列表中的"Debug Assertion Failed" "vector subscript out of range"
- 如何在没有参数列表的情况下定义向量无效使用模板名称 std::vector
- 打印逗号与std :: vector分开的列表
- 具有多个数组的类的构造函数启动器列表(C++11 是可以的,boost 和 std::vector 不是)
- std::vector for_each error C3867函数调用缺少参数列表
- 初始化类'中的std::vector;s初始值设定项列表
- 从 boost::mpl:vector 类型列表中定义成员变量
- 返回 vector<pair<int,int>> & from c++ 方法到 python 使用 swig typemap 的元组列表
- 使用Templates从参数列表创建std::vector