如何用Argv编写基于范围的for循环
How to Write the Range-based For-Loop With Argv?
来自c++0x维基百科网站:
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**&)’
我在Ubuntu 11.10上使用Qt和g++ 4.6.1。
c++中是否有Range类
基于范围的for循环语句定义冗余
通常,我对argc
和argv
做的第一件事是:
std::vector<std::string> arguments(argv, argv + argc);
现在我有了一个字符串向量来处理,我不仅可以很容易地使用基于范围的for循环,而且还可以使用c++标准库工具。
for(std::string& s : arguments) {
// do stuff...
}
维基百科代码工作,因为my_array
的类型是一个数组类型的变量。原来的代码不工作,因为argv
不是一个数组。语法char* argv[]
可能使它看起来像一个数组,但这只是C语法的一个可悲的产物。char* argv[]
与char** argv
完全相同。argv
不是数组;它实际上只是一个指针。
基于范围的for循环作用于:
- 数组;
- 具有返回迭代器的成员函数
begin()
和end()
的任何类型; - 任何存在非成员函数
begin
和end
的类型,可以像begin(x)
和end(x)
一样调用,x
是你迭代的东西。
如你所见,指针不属于这个列表。
您不知道,因为系统无法告诉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
是一个字符指针数组,其中任何一个都不应该被修改,每个都指向一个字符串,其中的任何字符也不应该被修改。
您可以使用c++ 20 std::span()
或gsl::span()
为argv
制作视图:
for (auto const arg : std::span(argv, argc)) {
std::cout << arg << 'n';
}
或者类似的,使用Ranges (std::view::counted()
):
for (auto const arg : std::views::counted(argv, argc)) {
std::cout << arg << 'n';
}
或者直接使用std::ranges::subrange
:
for (auto const arg : std::ranges::subrange{argv, argv+argc}) {
std::cout << arg << 'n';
}
建议的向量解决方案复制数组(仅复制指针,不复制字符串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);
请注意,所有这些变体都得益于字符串数组本身以空指针结束的事实,就像任何字符串都以空字符结束一样,因此*a
或*argv
的简单检查。
1这只适用于使用std::vector<char*>
;如果使用std::vector<std::string>
,就像实际建议的那样,甚至字符串本身也会被复制!
argv是双指针,argv**
因此,当&x创建对数组中元素的引用时,*arg不会创建引用,而是与argv中的每个元素的类型相同。
我想你会喜欢基于范围的循环,这样就不用写那么多了。
所以为了惹恼c++纯粹主义者,同时不完全回答你的问题,我们想发布一些很好的不安全的方法来做到这一点,没有任何std::vector
或oo包装垃圾:)
for (;argc--; argv++) {
printf(" %s n ", *argv);
}
或
while (argc--) {
printf(" %s n ", *(argv++));
}
或者
while (*argv) {
printf(" %s n ", *(argv++));
}
- 基于范围循环到旧编译器的旧样式
- 带有自定义对象的C 范围循环
- 为什么编译器不优化集合元素上的空范围循环?
- 迭代在包含向量的vor in for for范围循环中迭代
- 我们可以在范围循环中使用引用(而不是指针)上的删除
- 如何实现我的自定义范围循环
- C++范围循环
- GCC 4.4 不实现 C++11 范围循环.它还支持哪些其他范围循环语法
- 嵌套c++11范围循环,用于查找组合
- 范围循环中的访问索引
- 对于不可复制类型的范围循环,是否可能
- 我的范围循环出现逻辑错误
- 如何在我的类上允许范围循环
- c++的范围循环比递减循环快
- 通过范围循环从指针容器中获取取消引用元素的引用
- c++ 11:为什么这个范围循环会使FPS下降35
- 带有自定义类的范围循环(矢量的简单版本<string>,使用分配器)
- MSVC10 Visual Studio 2010支持c++范围循环吗?
- 围绕 2 的幂范围循环变量
- toupper() 在 for 范围循环中不起作用