2016-06-14 91 views
9

为什么这段代码:无法识别的基于范围的循环?

void printarray(int array[]) { 
    for (int x: array) { 
     std::cout << x << std::endl; 
    } 
} 

生成此编译时错误?

error: 'begin' was not declared in this scope 
    for (int x: array) { 

我对基于范围的for循环有什么问题?

+6

在这方面'int数组[]'确实不是数组,但相当于'INT * array'。在函数内部,我们不知道参数的大小。请参阅[在C编程语言中使用数组的大小](http://stackoverflow.com/questions/1975128/sizeof-an-array-in-the-c-programming-language) –

+0

使用最简单的方法:void printarray(std :: vector array){... –

+0

@Bo Persson是否可以嵌入函数帮助? – user6245072

回答

5

当一个数组作为函数的参数传递时,它会隐式转换为指向其第一个元素的指针。声明数组的参数也被调整为指针。

因此,例如,这些函数声明

void printarray(int array[100]); 
void printarray(int array[10]); 
void printarray(int array[]); 

声明的同一个功能,相当于

void printarray(int *array); 

所以你还需要数组的大小传递给函数,例如

void printarray(const int array[]. size_t n) 
{ 
    for (size_t i = 0; i < n; i++) 
    { 
     std::cout << a[i] << std::endl; 
    } 
} 

你可以写一个专门用于数组p的模板函数通过引用称职如例如

template <size_t N> 
void printarray(const int (&array)[N]) 
{ 
    for (int x : array) 
    { 
     std::cout << x << std::endl; 
    } 
} 

template <typename T, size_t N> 
void printarray(const T (&array)[N]) 
{ 
    for (auto x : array) 
    { 
     std::cout << x << std::endl; 
    } 
} 

但是与先前的函数它有一个缺点,因为不同大小的阵列是不同类型和编译器会生成从模板尽可能多的功能相比尽可能多的不同类型的数组将用于该函数。

而且您可以使用标准算法,例如std::copystd::for_each来输出数组。

例如

#include <iostream> 
#include <algorithm> 
#include <iterator> 

int main() 
{ 
    int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    std::copy(std::begin(array), std::end(array), 
       std::ostream_iterator<int>(std::cout, "\n")); 

    return 0; 
} 

另一种方法是使用标准的类std::array,其具有通过基于for语句的范围使用合适的成员函数beginend。例如

#include <iostream> 
#include <array> 

const size_t N = 10; 

void printarray(const std::array<int, N> &array) 
{ 
    for (int x : array) std::cout << x << std::endl; 
} 

int main() 
{ 
    std::array<int, N> array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    printarray(array); 

    return 0; 
} 

但在这种情况下,你也需要写一个模板函数,如果你要使用不同数量或类型的元素std::array类的输出对象。

例如

#include <iostream> 
#include <array> 

template <typename T, size_t N> 
void printarray(const std::array<T, N> &array) 
{ 
    for (auto x : array) std::cout << x << std::endl; 
} 

int main() 
{ 
    std::array<int, 10> array1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    printarray(array1); 

    std::array<char, 10> array2 = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' }; 

    printarray(array2); 

    return 0; 
} 
1

printarray接收的参数实际上是一个int *,范围不知道从哪里停止。在这种情况下,您将需要发送长度作为参数,并执行常规操作。

13

您的问题是array实际上不是数组。当你写

void printarray(int array[]) 

这是一样的

void printarray(int* array) 

既然你不能告诉多少个元素的指针指向而无需额外的大小参数,则不能使用远程基于for循环使用。

你需要做的是通过引用传递数组,以便数组不会衰变成指针。如果你知道数组的确切大小,那么你可以使用

void printarray(int (&array)[size_you_want_here]) 

如果你想使功能更加通用的,因此它可以与不同大小的数组工作,那么你可以使用一个模板像

template<std::size_t N> 
void printarray(int (&array)[N]) 

我上述两种情况下,你现在有一个实际的数组而不是一个指针,所以你可以使用它与基于范围的for循环。

另外请注意,我们可以使用

template<typename T, std::size_t N> 
void printarray(T (&array)[N]) { 
    for (auto&& x : array) { 
     std::cout << x << "\n"; 
    } 
} 

使功能完全通用的,您还会注意到我改变std::endl"\n"。通常,您不希望使用endl,因为它明确地在流上调用flush()。一般"\n"是你所需要的,最后如果输出还没有被刷新,那么你可以自己拨打flush()

+0

为什么'auto && x'虽然? – user6245072

+0

@ user6245072这只是出于习惯。你也可以使用'const auto&'使它成为只读和引用。 – NathanOliver