Как написать основанный на диапазоне For-Loop с Argv? - PullRequest
15 голосов
/ 20 декабря 2011

С сайта C ++ 0x Wikipedia:

int my_array[5] = {1, 2, 3, 4, 5};
for (int &x : my_array) {
    x *= 2;
}

Так почему этот код не работает?

int main(int argc, char* argv[])
{
    for (char *arg : argv)
    {
        // Do something.
    }
}

Ошибка:

main.cpp:36: error: no matching function for call to ‘begin(char**&)’

Я использую Qt с g ++ 4.6.1 в Ubuntu 11.10.

Дополнительная информация

Есть ли класс диапазона в C ++ 0x

Избыток определения оператора на основе диапазона для определения цикла

Ответы [ 4 ]

21 голосов
/ 20 декабря 2011

Обычно первое, что я делаю с argc и argv, это:

std::vector<std::string> arguments(argv, argv + argc);

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

for(std::string& s : arguments) {
    // do stuff...
}

Код Википедии работает, потому что тип my_array является переменной типа массива.Исходный код не работает, потому что argv не является массивом.Синтаксис char* argv[] может показаться массивом, но это просто печальный артефакт синтаксиса Си.char* argv[] равно точно так же, как char** argv.argv не является массивом;на самом деле это просто указатель.

Цикл for для диапазона работает с:

  • массивами;
  • любым типом, который имеет функции-члены begin() и end() которые возвращают итераторы;
  • любой тип, для которого существуют функции, не являющиеся членами begin и end, которые можно вызывать как begin(x) и end(x), причем x - это то, что вы 'повторяем.

Как видите, указатели не являются частью этого списка.

16 голосов
/ 20 декабря 2011

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

Хотя есть способ обойти это, и это создать собственный класс для переноса argv.Это даже не так сложно.

class argv_range {
 public:
   argv_range(int argc, const char * const argv[])
        : argc_(argc), argv_(argv)
   {
   }

   const char * const *begin() const { return argv_; }
   const char * const *end() const { return argv_ + argc_; }

 private:
   const int argc_;
   const char * const *argv_;
};

Вот как вы его используете:

for (const char *arg: argv_range(argc, argv)) {
   // Do something.
}

Да, я использую много const с.По сути, argv - это массив символьных указателей, ни один из которых не должен изменяться, каждый из которых указывает на строку, ни один из символов которого также не должен изменяться.

4 голосов
/ 15 марта 2016

Предлагаемое векторное решение копирует массив (только указатели, но не строки 1 - но все же).Unnessary.Решение argv_range - это то, что я бы тоже попробовал, если бы я абсолютно хотел использовать цикл на основе диапазона.Но это приводит к большому количеству дополнительного кода (допускается только один раз, если вы записываете его в заголовочный файл и сохраняете его, но все же).

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

for (char** a = argv; *a; ++a)
{
    // use *a, or if you don't like:
    char* arg = *a;
    // use arg...
}

Или, если вам больше не понадобится массив argv впоследствии:

for (++argv; *argv; ++argv)
{
    // use *argv, or if you don't like:
    char* a = *argv;
    // use a...
}

Существует небольшая разница, которую вы могли заметить: в первом варианте я перебираю все значения, во втором я пропускаю первое (обычно это имя программы, которую мыне заинтересованы во многих случаях).И наоборот, для каждого:

for (char** a = argv + 1; *a; ++a);
for (; *argv; ++argv);

1 Это применимо только при использовании std::vector<char*>;при использовании std::vector<std::string>, как на самом деле предлагается, копируются даже сами строки!

0 голосов
/ 20 декабря 2011

argv - это двойной указатель, argv **

Так что, где & x создает ссылку на элемент в массиве, ваш * arg не создает ссылку, а имеет тот же тип, что и каждый элемент в argv.

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