作为数组的函数参数传递的初始化列表
Initialiser list passed as function parameter for array
如何进行这项工作:
void foo(uint8_t a[]) { ... }
foo({0x01, 0x02, 0x03});
它给我一个错误:
error: cannot convert '<brace-enclosed initializer list>' to 'uint8_t* {aka unsigned char*}' for argument '1'
^
你不能。
刚构造
uint8_t a[] = {0x01, 0x02, 0x03};
并调用 foo(a)
.
或者直接使用std::array
,这可能更好。
这对我有用,我不得不更改函数签名,但在我的情况下它实际上更好,因为它静态检查数组长度:
void foo(std::array<uint8_t, 3> a) { /* use a.data() instead of a */ }
foo({0x01, 0x02, 0x03}); // OK
foo({0x01, 0x02}); // Works, at least on GCC 4.9.1. The third value is set to zero.
foo({0x01, 0x02, 0x03, 0x04}); // Compilation error.
到目前为止的答案还没有解决问题的主要问题:在签名中
void foo(uint8_t a[])
a
不是数组,而是指向uint8_t
的指针。尽管事实上 a
的声明使它看起来像一个数组。错误消息甚至指出了这一点:
cannot convert '<brace-enclosed initializer list>' to 'uint8_t* {aka unsigned char*}'
因此,同样不允许您这样做:
uint8_t *a = {0x01, 0x02, 0x03}; // Eek! Error
你不能用上面的签名调用foo({0x01, 0x02, 0x03});
。
我建议您花一些时间阅读 C 风格的数组以及它们在 C++ 中的表现 not first-class citizens。
从您发布到您自己的问题的答案来看,您似乎正在寻找适用于固定大小数组的函数。但不要按价值传递它!我建议使用以下声明:
void foo(std::array<uint8_t, 3> const &a);
这个:
void foo(uint8_t a[]) { ... }
是一个接受 uint8_t*
的函数,而不是数组 - 当用作函数参数时,数组会退化为指针。问题是初始化列表(如 {0x01, 0x02, 0x03}
)无法转换为 uint8_t*
。
如果您想要将任意数量的 uint8_t
传递给 foo
,简单的解决方案是使用新的 std::initializer_list
void foo(std::initializer_list<uint8_t> a) { ... }
foo({0x01, 0x02, 0x03, 0x04, 0x05}); // OK - a has 5 elems in it
或者您可以采用可变参数包并在内部从中构造一个数组:
template <typename... Args,
typename = std::enable_if_t<
all_true<std::is_convertible<Args, uint8_t>::value...>
>>
void foo(Args... elems) {
uint8_t a[] = {elems...};
// ...
}
用法略有不同:
foo({0x01, 0x02, 0x03}); // error
foo(0x01, 0x02, 0x03; // OK - a has 3 elems in it
foo(std::array<uint8_t, 3>{0x01, 0x02, 0x03}.data());
如何进行这项工作:
void foo(uint8_t a[]) { ... }
foo({0x01, 0x02, 0x03});
它给我一个错误:
error: cannot convert '<brace-enclosed initializer list>' to 'uint8_t* {aka unsigned char*}' for argument '1'
^
你不能。 刚构造
uint8_t a[] = {0x01, 0x02, 0x03};
并调用 foo(a)
.
或者直接使用std::array
,这可能更好。
这对我有用,我不得不更改函数签名,但在我的情况下它实际上更好,因为它静态检查数组长度:
void foo(std::array<uint8_t, 3> a) { /* use a.data() instead of a */ }
foo({0x01, 0x02, 0x03}); // OK
foo({0x01, 0x02}); // Works, at least on GCC 4.9.1. The third value is set to zero.
foo({0x01, 0x02, 0x03, 0x04}); // Compilation error.
到目前为止的答案还没有解决问题的主要问题:在签名中
void foo(uint8_t a[])
a
不是数组,而是指向uint8_t
的指针。尽管事实上 a
的声明使它看起来像一个数组。错误消息甚至指出了这一点:
cannot convert '<brace-enclosed initializer list>' to 'uint8_t* {aka unsigned char*}'
因此,同样不允许您这样做:
uint8_t *a = {0x01, 0x02, 0x03}; // Eek! Error
你不能用上面的签名调用foo({0x01, 0x02, 0x03});
。
我建议您花一些时间阅读 C 风格的数组以及它们在 C++ 中的表现 not first-class citizens。
从您发布到您自己的问题的答案来看,您似乎正在寻找适用于固定大小数组的函数。但不要按价值传递它!我建议使用以下声明:
void foo(std::array<uint8_t, 3> const &a);
这个:
void foo(uint8_t a[]) { ... }
是一个接受 uint8_t*
的函数,而不是数组 - 当用作函数参数时,数组会退化为指针。问题是初始化列表(如 {0x01, 0x02, 0x03}
)无法转换为 uint8_t*
。
如果您想要将任意数量的 uint8_t
传递给 foo
,简单的解决方案是使用新的 std::initializer_list
void foo(std::initializer_list<uint8_t> a) { ... }
foo({0x01, 0x02, 0x03, 0x04, 0x05}); // OK - a has 5 elems in it
或者您可以采用可变参数包并在内部从中构造一个数组:
template <typename... Args,
typename = std::enable_if_t<
all_true<std::is_convertible<Args, uint8_t>::value...>
>>
void foo(Args... elems) {
uint8_t a[] = {elems...};
// ...
}
用法略有不同:
foo({0x01, 0x02, 0x03}); // error
foo(0x01, 0x02, 0x03; // OK - a has 3 elems in it
foo(std::array<uint8_t, 3>{0x01, 0x02, 0x03}.data());