我最近写了一个函数模板,它引用了一个C数组:
template <class T,size_t N> void foo(T(&c_array)[N]);
假设T是一个字符,由于空终止符,C字符串的长度是N-1.我意识到我应该处理N == 0的边缘情况,因为N – 1将是std :: numeric_limits< std :: size_t> :: max().
所以为了避免在有些人将零长度的数组传递给这个函数的情况下可能发生的混乱,我把一个N == 0的检查.
然而,令我吃惊的是,似乎零长度的数组实际上甚至不是数组类型,或者至少这就是GCC似乎相信的.事实上,如果具有指针型签名的函数作为候选者,零长度数组甚至不会绑定到上述函数签名.
请考虑以下代码:
template <class T,size_t N> void foo(T(&array)[N]) { std::cout << "Array" << std::endl; } void foo(const void* p) { std::cout << "Pointer" << std::endl; } int main(int argc,char** argv) { char array1[10] = { }; const char* pointer = 0; char array2[0] = { }; foo(array1); foo(pointer); foo(array2); }
使用GCC 4.3.2,输出:
Array Pointer Pointer
奇怪的是,零长度数组更喜欢绑定到使用指针类型的函数.那么,这是GCC中的错误,还是C标准规定的一些晦涩的原因,为什么这种行为是必要的?
解决方法
由于数组必须具有大于零的长度,如果您的编译器错误地接受零大小的数组的定义,那么您将“安全地”超出语言标准的范围.没有必要处理N == 0的边缘情况.
这在C:8.3.5 [dcl.array]中是正确的:如果常量表达式(5.19)存在,它将是一个积分常量表达式,其值应大于零.