Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

size() of std::array pointer in constexpr context

Let's say I have a function like:

int test(std::array<char, 8>* data) {
  char buffer[data->size() * 2];

  [... some code ...]
}

clearly the size of the buffer can be evaluated at compile time: data has a constexpr size of 8 elements, 8 * 2 = 16 bytes.

However, when compiling with -Wall, -pedantic and -std=c++11 I get the infamous error:

warning: variable length arrays are a C99 feature [-Wvla-extension]

which I believe makes sense: array::size() is constexpr, but it is still a method, and in the function above we still have to dereference a pointer, which is not constexpr.

If I try something like:

int test(std::array<char, 8>& data) {
  char buffer[data.size() * 2];
  [...]
}

gcc (tried version 5.2.0) seems happy: there is no warning.

But with clang++ (3.5.1) I still get a warning complaining about variable length arrays.

In my case, I can't easily change the signature of test, it has to take a pointer. So... a few questions:

  1. What is the best / most standard way to get the size of a std::array pointer in constexpr context?

  2. Is the difference in behavior with pointers vs references expected? Which compiler is right about the warning, gcc or clang?

like image 328
rabexc Avatar asked Oct 06 '15 13:10

rabexc


1 Answers

I do not know about 2.

But for 1, we can do this:

template<class T, size_t N>
constexpr std::integral_constant<size_t, N> array_size( std::array<T, N> const& ) {
  return {};
}

then:

void test(std::array<char, 8>* data) {
  using size=decltype(array_size(*data));
  char buffer[size{}];
  (void)buffer;
  // [... some code ...]
}

alternatively:

template<class T, class U, size_t N>
std::array<T,N> same_sized_array( std::array< U, N > const& ) {
  return {};
}

void test(std::array<char, 8>* data) {
  auto buffer = same_sized_array<char>(*data);
  (void)buffer;
  // [... some code ...]
}

finally, a C++14 cleanup:

template<class A>
constexpr const decltype(array_size( std::declval<A>() )) array_size_v = {};

void test3(std::array<char, 8>* data) {
  char buffer[array_size_v<decltype(*data)>];
  (void)buffer;
  // [... some code ...]
}

Live example.

like image 165
Yakk - Adam Nevraumont Avatar answered Sep 21 '22 22:09

Yakk - Adam Nevraumont