Как показать, что переменная управления цикла не изменяется внутри тела цикла for C ++? - PullRequest
9 голосов
/ 23 ноября 2010

В C ++ допускается изменение переменной цикла внутри цикла for:

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

Теперь, если тело цикла довольно сложное, читателю не сразу понятно, будет ли изменена переменная цикла внутри тела цикла . Было бы неплохо как-то настроить код, чтобы, как только читатель увидел только заголовок цикла for, он сразу понял, что переменная цикла не изменяется внутри тела .

Например, если я использую const:

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

тогда ясно, что независимо от того, какой код написан ниже определения переменной const, переменная не изменяется.

Есть ли способ достичь чего-то подобного - логической константы внутри итерации - в случае управляющих переменных цикла for в C ++?

Ответы [ 9 ]

4 голосов
/ 23 ноября 2010

Я не думаю, что это возможно для созданного вручную цикла, но я предполагаю, что это можно считать дополнительным аргументом для поощрения использования std :: for_each и BOOST_FOREACH для итераций над контейнером STL.

РЕДАКТИРОВАТЬ ... и цикл C ++ 0x на основе диапазона for (спасибо Matthieu. M :)1011 *

2 голосов
/ 23 ноября 2010

Используйте 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
    });
2 голосов
/ 23 ноября 2010

C ++ 0x весело.Этот код не скомпилирован:

for (int i = 0; i < 10; ++i)
{
    [&, i] ()
    {
        if ( i == 5 )
        {
            ++i;
        }
        cout << i << endl;
    }();
}

Ошибка: 'i': захват не может быть изменен в неизменяемой лямбде

2 голосов
/ 23 ноября 2010

Это отличный вопрос, который заставил меня задуматься о том, как вы можете это сделать и как это обойти. Не тратя слишком много времени, я придумал только:

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

Очевидно, что пользователь все еще может изменить охрану в цикле, но, возможно, из-за того, что наверху показано, что он будет проверен.

1 голос
/ 23 ноября 2010

Создайте странный объект с макросом, который принимает FILE и LINE , последний возможно в качестве параметра шаблона (это постоянная времени компиляции?). При его увеличении должны использоваться те же FILE и LINE . Ну, одной и той же строки, вероятно, будет достаточно. Если это не в одной строке, вы можете получить ошибку компилятора.

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
}

Я не проверял это. Просто идея.

1 голос
/ 23 ноября 2010

Вы можете сделать все тело цикла for отдельной функцией, для которой переменная управления циклом выходит из области видимости.

Я не могу придумать простой способ сделать то, что вы хотите, поскольку переменная управления циклом может быть изменяемой по определению, чтобы управлять циклом.

1 голос
/ 23 ноября 2010

Технически вы можете сделать, например,

int main()
{
    for( int i = 0;  i < 42;  ++i )
    {{
        typedef void    i;

        i = 666;        // !Nope.
    }}
}

Если вы хотите получить доступ к i внутри тела цикла, вам нужно будет указать альтернативное имя (ссылаясь на const) перед typedef.

Но я не рекомендую это техническое решение, потому что оно неясно и не распространено, поэтому не очевидно для читателя.

Вместо этого просто рефакторинг больших циклов. : -)

1 голос
/ 23 ноября 2010

Не существует логической конструкции, обеспечивающей это.Если в качестве первого оператора в цикле указать «const int idx = i», а затем использовать только «idx», вы сможете добиться аналогичного применения, но потеряв некоторую ясность.В противном случае, просто используйте комментарии.

0 голосов
/ 23 ноября 2010

Вы можете попытаться изменить имя переменной «цикла» на что-то длинное и смешное, чтобы прикосновение к нему внутри цикла (более одного раза) поцарапало бы глаз.

Также некоторым нравится использовать макросы выделенного цикла, такие как BOOST_FOREACH. Это скрывает переменную цикла / итератор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...