6

How do I make this work:

void foo(uint8_t a[]) { ... }

foo({0x01, 0x02, 0x03});

It gives me an error:

error: cannot convert '<brace-enclosed initializer list>' to 'uint8_t* {aka unsigned char*}' for argument '1'
                                                     ^
3
  • The problem would have been clearer had you avoided the confusing uint8_t[] parameter "type" and written the more accurate uint8_t* instead. :) Commented Jul 21, 2015 at 11:25
  • Sorry yeah I'd normally use the pointer form but I was wondering if the compiler might perform some magic that I didn't know about if I used the array syntax instead. Commented Jul 21, 2015 at 19:20
  • Nope, 100% equivalence. Commented Jul 22, 2015 at 9:03

5 Answers 5

9

This worked for me, I had to change the function signature but it's actually better in my case as it statically checks the array length:

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.
Sign up to request clarification or add additional context in comments.

7 Comments

C-style arrays suck at everything. Always use std::array over them if possible.
Maybe you can use a template like template<int size> void foo(std::array<uint8_t, size> a){/*...*/}...(I haven't tried this way before..)
@Shindou not in this case, size parameter cannot be inferred.
@ForEveR I've just tested. we have to call it like foo<size>({/*...*/}); to make it work
@Shindou: Which is what he just said
|
6

The answers so far haven't addressed the main problem with the question: In the signature

void foo(uint8_t a[])

a is not an array, but a pointer to a uint8_t. This is despite the fact that the declaration of a makes it look like an array. This is even pointed out by the error message:

cannot convert '<brace-enclosed initializer list>' to 'uint8_t* {aka unsigned char*}'

So, in the same way you are not allowed to do this:

uint8_t *a = {0x01, 0x02, 0x03}; // Eek! Error

You can't call foo({0x01, 0x02, 0x03}); With the signature above.

I suggest you take some time to read up on C-style arrays and how they are not first-class citizens in C++.

From the answer you posted to your own question, it seems that you are looking for a function that works for fixed-size arrays. But don't pass it by value! I recommend using the following declaration:

void foo(std::array<uint8_t, 3> const &a);

Comments

4

You cannot. Just construct

uint8_t a[] = {0x01, 0x02, 0x03};

and call foo(a).

Or just use std::array, that is probably better.

Comments

3

This:

void foo(uint8_t a[]) { ... }

is a function that takes a uint8_t*, not an array - arrays are decayed to pointers when used as function arguments. The issue is that an initializer list (like {0x01, 0x02, 0x03}) cannot be converted to a uint8_t*.

If what you want is to pass an arbitrary number of uint8_ts to foo, the simple solution is to use the new std::initializer_list

void foo(std::initializer_list<uint8_t> a) { ... }

foo({0x01, 0x02, 0x03, 0x04, 0x05}); // OK - a has 5 elems in it

Or you could take a variadic pack and construct an array from it internally:

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...};
    // ...
}

That has slightly different usage:

foo({0x01, 0x02, 0x03}); // error
foo(0x01, 0x02, 0x03; // OK - a has 3 elems in it

Comments

0

foo(std::array<uint8_t, 3>{0x01, 0x02, 0x03}.data());

1 Comment

The std::array is created before the function and lives until the function returns.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.