C++ “迭代”成语;在每个连续的元素对之间“;

C++ “迭代”成语;在每个连续的元素对之间“;,c++,c++11,idioms,separator,C++,C++11,Idioms,Separator,每个人都会在某个时候遇到这个问题: for(const auto& item : items) { cout << item << separator; } for(常量自动&项目:项目){ cout我不知道这方面有什么特别的习惯用法。但是,我更喜欢先使用特殊的case,然后对其余的项执行操作 #include <iostream> #include <vector> int main() { std::vector&l

每个人都会在某个时候遇到这个问题:

for(const auto& item : items) {
    cout << item << separator;
}
for(常量自动&项目:项目){

cout我不知道这方面有什么特别的习惯用法。但是,我更喜欢先使用特殊的case,然后对其余的项执行操作

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> values = { 1, 2, 3, 4, 5 };

    std::cout << "\"";
    if (!values.empty())
    {
        std::cout << values[0];

        for (size_t i = 1; i < values.size(); ++i)
        {
            std::cout << ", " << values[i];
        }
    }
    std::cout << "\"\n";

    return 0;
}
#包括
#包括
int main()
{
向量值={1,2,3,4,5};

std::cout通常我的做法相反:

bool first=true;
for(const auto& item : items) {
    if(!first) cout<<separator;
    first = false;
    cout << item;
}
bool first=true;
用于(常量自动和项目:项目){

if(!first)cout从迭代中排除一个结束元素是Ranges proposal设计用来简化的事情(注意,有更好的方法来解决字符串连接的特定任务,从迭代中中断一个元素只会产生更多需要担心的特殊情况,例如当集合已经为空时)

当我们等待一个标准化的Ranges范例时,我们可以使用现有的rangefor和一个小的helper类来完成它

template<typename T> struct trim_last
{
    T& inner;

    friend auto begin( const trim_last& outer )
    { using std::begin;
      return begin(outer.inner); }

    friend auto end( const trim_last& outer )
    { using std::end;
      auto e = end(outer.inner); if(e != begin(outer)) --e; return e; }
};

template<typename T> trim_last<T> skip_last( T& inner ) { return { inner }; }
template struct trim\u last
{
T&inner;
朋友自动开始(最后一次和外部调整)
{使用std::begin;
返回开始(外部。内部);}
friend自动结束(最后一个和外部常量修剪)
{使用std::end;
自动e=结束(外部.内部);如果(e!=开始(外部))--e;返回e;}
};
模板trim_last skip_last(T&inner){return{inner};}
现在你可以写作了

for(const auto& item : skip_last(items)) {
    cout << item << separator;
}
用于(常量自动和项目:跳过最后一个(项目)){
cout我的方法(没有额外的分支)是:

const auto separator=“WhatYouWantHere”;
const auto*sep=“”;
用于(常量自动和项目:项目){
std::cout我不知道“惯用”,但C++11为双向迭代器提供了
std::prev
std::next
函数

int main() {
    vector<int> items = {0, 1, 2, 3, 4};
    string separator(",");

    // Guard to prevent possible segfault on prev(items.cend())
    if(items.size() > 0) {
        for(auto it = items.cbegin(); it != prev(items.cend()); it++) {
            cout << (*it) << separator;
        }
        cout << (*prev(items.cend()));
    }
}
intmain(){
向量项={0,1,2,3,4};
字符串分隔符(“,”);
//防止上一个(items.cend()上可能出现的SEG故障的防护装置
如果(items.size()>0){
for(auto it=items.cbegin();it!=prev(items.cend());it++){

我不认为你可以在某个地方有一个特例……例如,Boost有一个算法。如果你看它,你会看到第一个项目有一个特例(没有继续定界符),然后在每个后续元素之前添加一个then定界符。

你知道吗

intmain(){
int const items[]={21,42,63};
int const*项目=项目;
int const*const end=items+sizeof(items)/sizeof(items[0]);
//设备:
开关(1){

案例0:do{cout我喜欢简单的控制结构

if (first == last) return;

while (true) {
  std::cout << *first;
  ++first;
  if (first == last) break;
  std::cout << separator;
}
if(first==last)返回;
while(true){

std::cout您可以为_each_和_join定义一个以两个函子为参数的函数。第一个函子处理每个元素,第二个处理每对相邻元素:

#include <iostream>
#include <vector>

template <typename Iter, typename FEach, typename FJoin>
void for_each_and_join(Iter iter, Iter end, FEach&& feach, FJoin&& fjoin)
{
    if (iter == end)
        return;

    while (true) {
        feach(*iter);
        Iter curr = iter;
        if (++iter == end)
            return;
        fjoin(*curr, *iter);
    }
}

int main() {
    std::vector<int> values = { 1, 2, 3, 4, 5 };
    for_each_and_join(values.begin(), values.end()
    ,  [](auto v) { std::cout << v; }
    ,  [](auto, auto) { std::cout << ","; }
    );
}
#包括
#包括
模板
每项和每项连接无效(Iter Iter、Iter end、FEach和FEach、FJoin和FJoin)
{
如果(iter==结束)
返回;
while(true){
feach(*iter);
国际热核实验堆电流=国际热核实验堆;
如果(++iter==结束)
返回;
fjoin(*货币,*iter);
}
}
int main(){
向量值={1,2,3,4,5};
对于每个_和_连接(values.begin(),values.end())
,[](自动v){std::cout

目标是使用计算
&&
的方法。如果第一个条件为真,则计算第二个条件。如果不为真,则跳过第二个条件。

以下是我喜欢使用的小技巧:

对于双向可编辑对象:

for(自动it=items.begin();it!=items.end();it++)

{std::cout我喜欢
boost::join
函数。因此,对于更一般的行为,您需要为每对项调用一个函数,并且该函数可以具有持久状态。您可以将其用作带有lambda的function调用:

foreachpair (range, [](auto left, auto right){ whatever });
现在,您可以使用返回到基于
的常规范围的
循环

在这个想法中,
pair
被设置为原始集合的一对相邻元素。如果你有“abcde”,那么在第一次迭代中,你会得到第一个class='a'和第二个class='b';下一次是通过第一个class='b'和第二个class='c';等等

您可以使用类似的过滤器方法来准备一个元组,该元组使用/first/middle/last/iteration的枚举标记每个迭代项,然后在循环内进行切换


要简单地去掉最后一个元素,请对除最后一个之外的所有元素使用范围过滤器。我不知道这是否已经在Boost.range中,或者Rangev3正在提供什么,但这是使常规循环变戏法并使其“整洁”的一般方法.

这里的反应完全相同;也适用于任何可以作为列表开头和结尾的语言。需要注意的是,该循环可以写成
for(const auto&item:skip_first(values))
…以满足问题的要求。@einpoklum是的,谢谢。我已经纠正了打字错误。@BenVoigt:Is
skip_first
a(假设)我们必须定义的函数,或者有一个C++函数来完成所需要的功能吗?@ RyKAP:我正忙着写它,看看我的答案。如果你想从函数编程书中取一页,你可以一直使用,尽管这往往是多余的,但是很多TimeC++没有算法>代码>连接<代码>。这是一个巨大的耻辱。@代码Kavew,<代码>折叠< /Cord>不会帮助你——它将对每个元素应用操作,包括第一个和最后一个。@ Sergya如果你注意到,除了连接方法之外,Cube的C++实现需要3个参数,所以你只需从第二个元素到最后一个元素,并将第一个元素作为基元。元素。这样就可以了。事实上,用分隔符分隔某个元素就是链接中的一个例子。@SergeyA:我同意当容器为空时不能调用
std::acculate
,但一个元素应该就可以了(单个元素作为
init
传递,而
int main() {
    vector<int> items = {0, 1, 2, 3, 4};
    string separator(",");

    // Guard to prevent possible segfault on prev(items.cend())
    if(items.size() > 0) {
        for(auto it = items.cbegin(); it != prev(items.cend()); it++) {
            cout << (*it) << separator;
        }
        cout << (*prev(items.cend()));
    }
}
int main() {
  int const items[] = {21, 42, 63};
  int const * item = items;
  int const * const end = items + sizeof(items) / sizeof(items[0]);
  // the device:
  switch (1) {
    case 0: do { cout << ", ";
    default: cout << *item; ++item; } while (item != end);
  }

  cout << endl << "I'm so sorry" << endl;
  return 0;
}
template<typename Iterator, typename Fn1, typename Fn2>
void for_the_device(Iterator from, Iterator to, Fn1 always, Fn2 butFirst) {
  switch ((from == to) ? 1 : 2) {
    case 0:
      do {
        butFirst(*from);
    case 2:
        always(*from); ++from;
      } while (from != to);
    default: // reached directly when from == to
      break;
  }
}
int main() {
  int const items[] = {21, 42, 63};
  int const * const end = items + sizeof(items) / sizeof(items[0]);
  for_the_device(items, end,
    [](auto const & i) { cout << i;},
    [](auto const & i) { cout << ", ";});
  cout << endl << "I'm (still) so sorry" << endl;
  // Now on an empty range
  for_the_device(end, end,
    [](auto const & i) { cout << i;},
    [](auto const & i) { cout << ", ";});
  cout << "Incredibly sorry." << endl;
  return 0;
}
if (first == last) return;

while (true) {
  std::cout << *first;
  ++first;
  if (first == last) break;
  std::cout << separator;
}
...
while (true) {
  std::cout << *first;
  if (++first == last) break;
  std::cout << separator;
}
#include <iostream>
#include <vector>

template <typename Iter, typename FEach, typename FJoin>
void for_each_and_join(Iter iter, Iter end, FEach&& feach, FJoin&& fjoin)
{
    if (iter == end)
        return;

    while (true) {
        feach(*iter);
        Iter curr = iter;
        if (++iter == end)
            return;
        fjoin(*curr, *iter);
    }
}

int main() {
    std::vector<int> values = { 1, 2, 3, 4, 5 };
    for_each_and_join(values.begin(), values.end()
    ,  [](auto v) { std::cout << v; }
    ,  [](auto, auto) { std::cout << ","; }
    );
}
int a[3] = {1,2,3};
int size = 3;
int i = 0;

do {
    std::cout << a[i];
} while (++i < size && std::cout << ", ");
1, 2, 3 
foreachpair (range, [](auto left, auto right){ whatever });
for (auto pair : collection|aspairs) {
    Do-something_with (pair.first);
}