给出最小的C++ 11 STL示例:
set<int> S = {1,2,3,4};
for(auto &x: S) {
cout << x;
cout << ",";
}
Run Code Online (Sandbox Code Playgroud)
有没有办法x在结束前检查是否正确?此示例中的目标是输出1,2,3,4而不是最后的最后一个逗号.目前我使用带有两个迭代器的标准for循环,
set<int>::const_iterator itr;
set<int>::const_iterator penultimate_end_itr = --S.end();
for(itr=S.begin(); itr!=penultimate_end_itr;++itr)
cout << (*itr) << ',';
cout << (*penultimate_end_itr);
Run Code Online (Sandbox Code Playgroud)
哪个有效,但非常麻烦.有没有办法在基于范围的for循环中进行检查?
编辑:问题的关键是不打印逗号分隔列表.我想知道基于范围的for循环是否具有列表中倒数第二个元素的任何知识(即它是在结束之前的一个).提出了最小的例子,所以我们都有一个共同的代码块来讨论.
use*_*136 18
基于范围的for循环的目的是忘记迭代器.因此,它们只允许您访问当前值而不是迭代器.以下代码会为您执行此操作吗?
set<int> S = {1,2,3,4};
std::string output;
for(auto &x: S) {
if (!output.empty())
output += ",";
output += to_string(x);
}
cout << output;
Run Code Online (Sandbox Code Playgroud)
编辑
另一个解决方案:您可以比较值的地址,而不是比较迭代器(就像循环的"正常").
set<int> S = {1,2,3,4};
auto &last = *(--S.end());
for (auto &x : S)
{
cout << x;
if (&x != &last)
cout << ",";
}
Run Code Online (Sandbox Code Playgroud)
Boost.Range可以在这里提供帮助:
if (std::begin(S) != std::end(S)) {
std::cout << *std::begin(S);
for (const auto &x: boost::make_iterator_range(std::next(std::begin(S)), std::end(S))) {
std::cout << ", " << x;
}
}
Run Code Online (Sandbox Code Playgroud)
一种更灵活的方法是使用boost::adaptors::indexed(自Boost 1.56起)索引范围:
for (const auto &element: boost::adaptors::index(S)) {
std::cout << (element.index() ? ", " : "") << element.value();
}
Run Code Online (Sandbox Code Playgroud)
在1.56之前的Boost版本中boost::adaptors::indexed不起作用,但你可以轻松编写类似的工作:
template <typename... T>
auto zip(const T&... ranges) -> boost::iterator_range<boost::zip_iterator<decltype(boost::make_tuple(std::begin(ranges)...))>>
{
auto zip_begin = boost::make_zip_iterator(boost::make_tuple(std::begin(ranges)...));
auto zip_end = boost::make_zip_iterator(boost::make_tuple(std::end(ranges)...));
return boost::make_iterator_range(zip_begin, zip_end);
}
template<typename T>
auto enumerate(const T &range) -> boost::iterator_range<boost::zip_iterator<boost::tuple<
boost::counting_iterator<decltype(boost::distance(range))>, decltype(std::begin(range))>>>
{
return zip(boost::make_iterator_range(boost::make_counting_iterator(0),
boost::make_counting_iterator(boost::distance(range))), range);
}
for (const auto &tup: enumerate(S)) {
std::cout << (tup.get<0>() ? ", " : "") << tup.get<1>();
}
Run Code Online (Sandbox Code Playgroud)
这是使用zip来自c ++ 11的Sequence-zip函数的函数?