固定大小和零初始化数组作为 C++11 中的默认参数

Joa*_*rén 0 c++ arrays initializer-list default-arguments c++11

上下文:我认为使用以下编译的SSCCEcompile: g++ -std=c++11 main.cpp将对固定大小的数组进行零初始化arr

void foo(int arr[4] = {0}) { }

int main(int argc, char const *argv[]) {
    foo();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

然而,我调试gdb并发现arr = 0x0(空)。我(疯狂地)猜测这是因为int arr[4]很像,int* arr但另外告诉编译器只允许长度为 4 的数组。因此,实际发生的情况是,int arr* = {0}即我只是使用初始化列表来对指针进行零初始化。

我知道我可以通过恢复使用重载而不是默认参数来规避这个问题:

void foo(int arr[4]) { }

void foo() {
    int arr[4] = {0};
    foo(arr);
}
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,这确实给了我一个零初始化的固定大小数组foo。然而,我认为通过使用一些默认参数将这两个重载函数合并为一个函数会很好,类似于 SSCCE。

问题:C++11 中默认参数固定大小数组的零初始化是否可行。如果是这样,怎么办?

Unh*_*eep 5

您遇到的主要问题是void foo(int arr[4])衰减为void foo(int* arr),因此您的函数实际上接受指针而不是数组。简单的证明是foo(nullptr);编译时不会出现错误或警告。

因此,该声明void foo(int arr[4] = {0});实际上将void foo(int* arr = {0});指针初始化为 0(尝试更改{0}为任何其他数字实际上会导致编译时错误)。

最好的替代方案最有可能使用std::array,例如:

#include <array>

void foo(std::array<int, 4> arr = {0}) { }

int main(int argc, char const *argv[]) {
    foo();
    // call with an array
    foo({1,2,3,4});
    // providing more values will cause a compile time error
    // foo({2,3,4,5,6,7,8});
    return 0;  
}
Run Code Online (Sandbox Code Playgroud)

请注意,目前没有方便的方法将“原始”C 样式数组转换为 std::array,尽管调用了一个辅助函数,experimental/arraystd::to_array函数可能会在未来版本中合并到标准中