如何使用Argv编写基于范围的For循环?

IAE*_*IAE 15 c++ for-loop c++11

来自c ++ 0x维基百科网站:

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

那么为什么这段代码不起作用呢?

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

错误:

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

我在Ubuntu 11.10上使用Qt和g ++ 4.6.1.

附加信息

C++ 0x中是否有范围类

基于范围的For-Loop语句定义冗余

R. *_*des 23

通常情况下,我做的第一件事argcargv是这样的:

std::vector<std::string> arguments(argv, argv + argc);
Run Code Online (Sandbox Code Playgroud)

现在我有一个可以使用的字符串向量,我不仅可以轻松使用基于范围的for循环,还可以使用C++标准库工具.

for(std::string& s : arguments) {
    // do stuff...
}
Run Code Online (Sandbox Code Playgroud)

维基百科代码有效,因为类型my_array是数组类型的变量.原始代码不起作用,因为argv它不是数组.语法char* argv[]可能使它看起来像是一个数组,但这只是一个C语法的悲伤工件.char* argv[]完全相同一样char** argv.argv不是一个数组; 它实际上只是一个指针.

基于范围的for循环适用于:

  • 阵列;
  • 任何具有成员函数begin()end()返回迭代器的类型;
  • 任何类型而存在非成员函数beginend,可以这样调用begin(x)end(x),与x是,你要遍历的事情.

如您所见,指针不是此列表的一部分.


Omn*_*ous 16

你没有,因为系统无法判断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_;
};
Run Code Online (Sandbox Code Playgroud)

以下是您使用它的方式:

for (const char *arg: argv_range(argc, argv)) {
   // Do something.
}
Run Code Online (Sandbox Code Playgroud)

是的,我使用了很多consts.基本上,argv是一个字符指针数组,其中没有一个应该被修改,每个都指向一个字符串,其中任何一个字符都不应该被修改.

  • 如果Boost可用,你可以改为`auto argv_range = [](size_t len,char const*const ptr){return boost :: make_iterator_range(ptr,ptr + len); }或等效函数.我使用lambda只是为了避免拼写返回类型,即`boost :: iterator_range <char const*const>`. (4认同)

Mon*_*Tuk 9

您可以使用 C++20std::span()gsl::span()为以下内容创建视图argv

for (auto const arg : std::span(argv, argc)) {
    std::cout << arg << '\n';
}
Run Code Online (Sandbox Code Playgroud)

或类似的,使用范围( std::view::counted()):

for (auto const arg : std::views::counted(argv, argc)) {
    std::cout << arg << '\n';
}
Run Code Online (Sandbox Code Playgroud)

或直接使用std::ranges::subrange

for (auto const arg : std::ranges::subrange{argv, argv+argc}) {
    std::cout << arg << '\n';
}
Run Code Online (Sandbox Code Playgroud)


Aco*_*gua 5

提出的向量解决方案复制数组(仅指针,而不是字符串1 - 但仍然)。不雅。如果我绝对想强制执行基于范围的循环,我也会尝试使用 argv_range 解决方案。但这会产生很多额外的代码(承认,只有一次,如果您将其写入头文件并保留它,但仍然如此)。

经典循环对我来说似乎很简单,我允许自己发布它,我认为仅仅为了拥有一个基于范围的循环而付出所有这些努力是不值得的......

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

或者,如果您以后不再需要 argv 数组:

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

有一点不同,您可能已经注意到:在第一个变体中,我遍历所有值,在第二个变体中,我省略了第一个(通常是我们在许多情况下不感兴趣的程序名称)。反过来,对于每个:

for (char** a = argv + 1; *a; ++a);
for (; *argv; ++argv);
Run Code Online (Sandbox Code Playgroud)

1这仅适用于,如果使用std::vector<char*>; 如果使用std::vector<std::string>,正如实际建议的那样,甚至字符串本身也会被复制!