简体   繁体   English

for(auto) loop in print function 抛出错误,为什么?

[英]for(auto) loop in print function is throwing an error, why?

The for loop in main compiles fine but in the print function it doesn't, with the diagnostic main中的for循环编译正常,但在打印 function 中它没有,带有诊断

for(auto i:x) cout<<i<<" ";        

  -----------^std::end  
'end' was not declared in this scope; did you mean 'std::end'?

being issued.正在发行。 Here's the full code:这是完整的代码:

#include <iostream>
void print(int x[],int n)
{
   for(auto i:x) std::cout<<i<<" ";
}

int main()
{
    int arr[] = {1, 5, 2, 1, 4, 3, 1, 7, 2, 8, 9, 5};
    int n = sizeof(arr) / sizeof(int);
    for(auto i:arr)
        std::cout<<i<<" ";
    print(arr, n);
    return 0;
}

The issue is that the array arr decays to a pointer when passed to the function print .问题是数组arr在传递给 function print衰减为指针。 The mechanism behind the range-based for loop is via the use of std::begin and std::end .基于范围的for循环背后的机制是通过使用std::beginstd::end That goes some way in explaining the compiler diagnostic: they don't work if applied to pointer types.这在某种程度上解释了编译器诊断:如果应用于指针类型,它们将不起作用。

This pointer decay is the normal behavior when passing array parameters to functions, but is by no means universal.这种指针衰减是将数组参数传递给函数时的正常行为,但绝不是普遍的。 For example, std::begin and std::end obviate this with some template trickery (otherwise they'd be useless for array types), something which you can do too by writing例如, std::beginstd::end通过一些模板技巧来避免这种情况(否则它们对数组类型毫无用处),您也可以通过编写来做到这一点

template<typename T>
void print(T&& x, int n)
{
   for(auto i:x) std::cout<<i<<" ";
}

instead.反而。

The plain old datatype int[] has no end-iterator , if you pass it to a function. In this case you yust pass a pointer to the first item.如果将普通旧数据类型 int[] 传递给 function,则它没有end-iterator 。在这种情况下,您必须传递指向第一项的指针。 In order to use a range based for loop you have to use a data container, which has a begin- and end-iterator, such as std::vector为了使用基于范围的 for 循环,您必须使用数据容器,它具有开始和结束迭代器,例如std::vector

Here is your code in a more C++ way.是您的代码更多C++方式。

#include<vector>
#include<iostream>
    
void print(const std::vector<int> &x) {
    for(auto i:x) {
       std::cout<<i<<" ";
    }
}

int main() {
    const std::vector<int> arr {1, 5, 2, 1, 4, 3, 1, 7, 2, 8, 9, 5};
    for(auto i:arr) {
        std::cout << i << " ";
    }

    print(arr);
    return 0;
}

@schorsch312's answer is correct, but the suggestion to have the print() function take an std::vector is not the "C++ way": Using std::vector instead of a plain array in your main program is just fine, but when writing a function - I would recommend not to take a type more specific than what you actually need to perform the function's work, and specifically not allocate memory on the heap with a new vector. @schorsch312 的回答是正确的,但是让print() function 采用std::vector的建议不是“C++ 方式”:在主程序中使用std::vector而不是普通数组就可以了,但是当编写 function - 我建议不要采用比执行函数工作实际需要的类型更具体的类型,特别是不要使用新向量在堆上分配 memory。

For the case of you having a C array in your program, @Bathsheba's suggestion of a print() is better in my opinion, in that it will allow you to pass the array as-such, and thus iterate over it properly.对于你的程序中有一个 C 数组的情况,我认为 @Bathsheba 的print()建议更好,因为它允许你按原样传递数组,从而正确地迭代它。

However - for pedagogical reasons, I would suggest you consider this version print() :但是 - 出于教学原因,我建议您考虑这个版本print()

template <std::size_t N>
void print(const int (&arr)[N]) {
    for(auto i : arr) {
       std::cout << i << " ";
    }
}

which illustrates how print() can take an array reference.这说明了print()如何获取数组引用。 You need the template when you don't know the array size apriori.当您不知道阵列大小先验时,您需要模板。 (and this also works of course.) (这当然也有效。)

Alternatively, you could use the standard library algorithm, std::for_each , like so:或者,您可以使用标准库算法std::for_each ,如下所示:

#include <vector>
#include <iostream>
#include <algorithm>

int main()
{
    int arr[] {1, 5, 2, 1, 4, 3, 1, 7, 2, 8, 9, 5};
    for(auto i:arr) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
    std::for_each(
        std::begin(arr), std::end(arr),
        [](auto i) { std::cout << i << ' '; }
    );
}

Note that when you use the ranged-for loop, what happens is basically the equivalent of the for_each invocation, or of a raw for loop over an iterator beginning at std::begin(arr) and ending at std::end(arr) .请注意,当您使用 ranged-for 循环时,所发生的基本上等同于for_each调用,或者等同于从std::begin(arr)std::end(arr)结束的迭代器上的原始 for 循环.

Yet another alternative - which does not require concerning yourself with iterator pairs - is to have a print() function taking a span ( What is a "span" and when should I use one? ).还有另一种选择——不需要关心迭代器对——是让print() function 取一个span什么是“跨度”,我什么时候应该使用一个? )。 Here it makes some sense since a plain C array can be referred to by a span: It has contiguous element storage and a specific length.在这里它是有道理的,因为一个普通的 C 数组可以被一个跨度引用:它有连续的元素存储和特定的长度。 If you were to be using C++20, your span-using print function would look like this:如果您要使用 C++20,您的 span-using print function 将如下所示:

#include <span> 

void print(const std::span<int> &sp) {
    for(auto i : sp) {
       std::cout << i << ' ';
    }
}

and again you don't have to specify the length in your main function. C++14 doesn't have spans in the standard library, but the C++ Guidelines Support Library (see here or here ) has it, as gsl::span - and it works in C++14.同样,您不必在主 function 中指定长度。C++14 在标准库中没有跨度,但 C++ 指南支持库(请参阅此处此处)有它,如gsl::span - 并且它在 C++14 工作。


Nitpicks:挑剔:

  • There is no need to return 0 from main() - that happens automatically.无需从main() return 0 - 这会自动发生。
  • Please use spaces between #include directives and the angle-brackets (ie #include <foo> , not #include <foo> .请在#include指令和尖括号之间使用空格(即#include <foo> ,而不是#include <foo>
  • Please use spaces before and after << operators.请在<<运算符前后使用空格。
  • To print a space, you don't need a string;要打印空格,您不需要字符串; the single space character suffices, ie std::cout << ' ' rather than std::cout << " " .单个空格字符就足够了,即std::cout << ' '而不是std::cout << " "

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM