Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Write the Range-based For-Loop With Argv?

From the c++0x Wikipedia site:

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

So why does this code not work?

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

Error:

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

I am using Qt with g++ 4.6.1 on Ubuntu 11.10.

Additional Information

Is There a Range Class in C++0x

Range-Based For-Loop Statement Definition Redundance

like image 658
IAE Avatar asked Dec 20 '11 09:12

IAE


People also ask

What is a range based loop?

Range-based for loop in C++ is added since C++ 11. It executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.

What does colon mean in for loop C++?

Colon ':' is basically a operator which indicates that the y is inside x and assign the y's value to the elements of array one by one.

What format is argv?

argv(ARGument Vector) is array of character pointers listing all the arguments. If argc is greater than zero,the array elements from argv[0] to argv[argc-1] will contain pointers to strings. Argv[0] is the name of the program , After that till argv[argc-1] every element is command -line arguments.

Is range based for loop faster?

Range-for is as fast as possible since it caches the end iterator[citationprovided], uses pre-increment and only dereferences the iterator once. Then, yes, range-for may be slightly faster, since it's also easier to write there's no reason not to use it (when appropriate).


2 Answers

Usually, the first thing I do with argc and argv is this:

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

Now I have a vector of strings to work with and I can easily use not only the range-based for loops, but also C++ standard library facilities.

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

The wikipedia code works because the type of my_array is a variable of array type. The original code does not work, because argv is not an array. The syntax char* argv[] may make it look like it is an array, but that's just a sad artifact of C syntax. char* argv[] is exactly the same as char** argv. argv is not an array; it's actually just a pointer.

The range-based for loop works on:

  • arrays;
  • any type that has member functions begin() and end() that return iterators;
  • any type for which exist non-member functions begin and end that can be called like begin(x) and end(x), with x being the thing that you're iterating over.

As you can see, pointers are not part of this list.

like image 63
R. Martinho Fernandes Avatar answered Oct 02 '22 04:10

R. Martinho Fernandes


You don't, because the system can't tell how long argv is at compile time. Someone can likely find the proper section of the standard to quote you about this.

There is a way around it though, and that's to create a custom class to wrap argv. It's not even that hard.

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_;
};

Here's how you use it:

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

Yeah, I use a lot of consts. Basically, argv is an array of character pointers, none of which should be modified, each pointing to a string, none of the characters of which should be modified either.

like image 20
Omnifarious Avatar answered Oct 02 '22 05:10

Omnifarious