36

Is the following a valid C++ code, and why not?

std::array<std::string, 42> a1;
std::array<int, a1.size()> a2;

It doesn't compile in GCC 4.8 (in C++11 mode). There is a simple but inelegant workaround:

std::array<std::string, 42> a1;
std::array<int, sizeof(a1)/sizeof(a1[0])> a2;

So clearly the compiler can figure out the number of elements in std::array. Why std::array::size() is not a constexpr static function?

EDIT: I have found another workaround:

std::array<std::string, 42> a1;
std::array<int, std::tuple_size<decltype(a1)>::value> a2;
robson3.14
  • 3,028
  • 2
  • 20
  • 19

5 Answers5

24

array<T>::size() is constexpr, but you can't use it in this way because a1 isn't a constexpr value. Additionally, it can't be constexpr because string isn't a literal type.

However, you can work around this if you want, by deducing the size_t template parameter. Example:

#include <string>
#include <array>
#include <iostream>
using namespace std;

template<typename>
struct array_size;
template<typename T, size_t N>
struct array_size<array<T,N> > {
    static size_t const size = N;
};

array<string, 42> a1;
array<string, array_size<decltype(a1)>::size> a2;

int main() {
    cout << a2.size() << endl;
}
Adam H. Peterson
  • 4,511
  • 20
  • 28
  • 10
    And that's why `size()` should be a `static` function, as suggested in the question. – Ben Voigt May 31 '13 at 21:19
  • @BenVoigt If size was a static constexpr function, there would be no problem? – robson3.14 May 31 '13 at 22:23
  • 1
    @robson: Right, because then it would be `constexpr` depending only on whether all arguments are `constexpr` (trivially met since there are zero arguments) and not depending on whether the object instance `*this` is `constexpr`. – Ben Voigt Jun 01 '13 at 00:34
  • 13
    In fact, there is such a `array_size` deducing template already in the standard library: [`std::tuple_size::value`](https://en.cppreference.com/w/cpp/utility/tuple/tuple_size) (C++11). In C++17, you'll additionally find the usual convenience helper `std::tuple_size_v`. – burnpanck Mar 17 '19 at 08:14
11

std::array::size is actually required to be constexpr per § 23.3.2.1 of the C++11 standard:

23.3.2.4 array::size [array.size]  
template <class T, size_t N> constexpr size_type array<T,N>::size() noexcept;  
Returns: N

I'm guessing this just slipped past whoever implemented it in GCC.


After testing, this works:

std::array<int, 42> a1;
std::array<int, a1.size()> a2;

This may actually have something to do with std::string not being a valid constexpr type to make compile-time instances of, whereas int is.

chris
  • 60,560
  • 13
  • 143
  • 205
4

You can use the same template-inference method as has always been used for C++98 array bound detection.

template<size_t N, typename T>
constant_integer<N> array_size( const std::array<T, N>& );

Make a nice macro wrapper and enjoy!

Many variations are also possible, such as:

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
0

It is not static but it is a constexpr http://www.cplusplus.com/reference/array/array/size/
EDIT: this may not be a bug, take a look at this Error using a constexpr as a template parameter within the same class

Community
  • 1
  • 1
aaronman
  • 18,343
  • 7
  • 63
  • 78
0

std::tuple_size has a specialization for std::array for this purpose:

std::array<int, 42> a1;
std::array<int, std::tuple_size<decltype(a1)>::value> a2;

Since C++17 can use a shorthand std::tuple_size_v:

std::array<int, 42> a1;
std::array<int, std::tuple_size_v<decltype(a1)>> a2;
rustyx
  • 80,671
  • 25
  • 200
  • 267