【问题标题】:How to show that a loop control variable is not changed inside the C++ for-loop body?如何显示循环控制变量在 C++ for 循环体内没有改变?
【发布时间】:2010-11-23 11:45:41
【问题描述】:

在 C++ 中,允许在 for 循环中更改循环变量:

for( int i = 0; i < limit; i++ ) {
    if( condition ) {
       i--;
    }
}

现在,如果循环体相当复杂,读者不会立即明白循环变量是否在循环体内部发生了变化。最好以某种方式调整代码,这样一旦读者只看到 for-loop 标头,他就会立即知道循环变量没有在 在主体内发生变化。

例如,如果我使用const

const int value = computeValue();
//lots of code here

那么很明显,无论在const 变量定义下面写什么代码,该变量都不会改变。

在 C++ 中的 for-loop 控制变量的情况下,有没有办法实现类似的东西 - 迭代中的逻辑常量?

【问题讨论】:

  • 我相信std::for_each 可以做到这一点。
  • 我使用BOOST_FOREACH 取得了巨大成功。你甚至可以在你的预编译头文件中引入一个方便的#define foreach BOOST_FOREACH

标签: c++ loops for-loop constants


【解决方案1】:

我认为这对于手工制作的循环来说是不可能的,但我猜想这可以被视为一个额外的论据,以鼓励使用 std::for_eachBOOST_FOREACH 在 STL 容器上进行迭代。

EDIT ...和 ​​C++0x range-based for-loop(感谢 Matthieu。M :)

【讨论】:

  • 如果希望保证循环体中的循环计数器不被修改,那么看在上帝的份上就这么做。我在回答中展示了一种方式,还有其他方式。但是不要做这种连目的都达不到的 Rube Goldberg 的事情。
  • @Alf:显然,正如我回答中的“愚蠢解决方案”标签所述,我永远不会在“真实”代码中推荐类似的东西
  • @icecrime:抱歉,我没听懂这个笑话。今天脑子很慢。对不起。
  • @icecrime:添加新的基于范围的循环构造en.wikipedia.org/wiki/C%2B%2B0x#Range-based_for-loop
【解决方案2】:

这是一个很好的问题,让我思考了如何做到这一点以及解决它的方法。没有花太多时间,我唯一想到的是:

int limit = 10;
for(int i(0), guard(0); i < limit; i++, guard++)
{
         // lots of code here
    assert(i == guard);
}

显然,用户仍然可以在循环中修改保护,但也许顶部的意图表明它将被检查。

【讨论】:

    【解决方案3】:

    将 for_each 与 boost::counting_iterator 和一个接受 const int 的函数结合使用。

    for_each(boost::counting_iterator<int>(0), boost::counting_iterator<int>(limit),
        [&](const int i)
        {
            // do something with i
        });
    

    【讨论】:

    • 我认为使用 C++0x,你可以做到 typedef boost::counting_iterator&lt;int&gt; bcii; for (const int i : std::make_pair(bcii(0), bcii(limit))) { ... }
    【解决方案4】:

    C++0x 很有趣。此代码未编译:

    对于 (int i = 0; i

    错误: 'i':不能在非可变 lambda 中修改按值捕获

    【讨论】:

      【解决方案5】:

      没有逻辑结构可以强制执行此操作。如果您将“const int idx = i”作为循环中的第一条语句,然后仅使用“idx”,您可能能够实现类似的执行,但会失去一些清晰度。否则,只需使用 cmets。

      【讨论】:

        【解决方案6】:

        您可以使整个 for 循环体成为一个单独的函数,循环控制变量超出范围。

        我想不出一种简单的方法来做你想做的事,因为循环控制变量是定义可变的,以便控制循环。

        【讨论】:

          【解决方案7】:

          使用带有FILELINE的宏创建一个奇怪的对象,后者可能作为模板参数(它是编译时间常数吗?)。当您增加它时,它必须使用相同的 FILELINE。那么同一行可能就足够了。如果它不在同一行,您可能会收到编译器错误。

          template< int line > 
          class Counter
          {
           // stuff
          public:
             bool valid() const;
             static void inc( Counter<line> & counter );  
          };
          
          for( Counter<__LINE__> counter( n ); counter.valid(); Counter<__LINE__>::inc( counter ) )
          {
           // body
          
             // what __LINE__ do I need to use here to increment counter? Can be done but won't be
          }
          

          我没有测试过。只是一个想法。

          【讨论】:

            【解决方案8】:

            技术上你可以这样做,例如

            int main()
            {
                for( int i = 0;  i < 42;  ++i )
                {{
                    typedef void    i;
            
                    i = 666;        // !Nope.
                }}
            }
            

            如果您想访问循环体内的i,则必须在typedef 之前提供一个备用名称(指const)。

            但我不推荐这种技术方案,因为它晦涩难懂,不常见,对读者来说并不明显。

            相反,只需重构大循环。 :-)

            【讨论】:

              【解决方案9】:

              您可以尝试将您的“循环”变量名称更改为长而可笑的名称,以便在循环内(不止一次)触摸它会划伤眼睛。

              还有一些喜欢使用专用循环宏,例如BOOST_FOREACH。这隐藏了循环变量/迭代器。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2020-03-01
                • 1970-01-01
                • 1970-01-01
                • 2017-06-21
                • 1970-01-01
                • 1970-01-01
                • 2016-09-06
                相关资源
                最近更新 更多