39

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; 
0

5 Answers 5

26

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

4 Comments

And that's why size() should be a static function, as suggested in the question.
@BenVoigt If size was a static constexpr function, there would be no problem?
@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.
In fact, there is such a array_size deducing template already in the standard library: std::tuple_size<some_array_type>::value (C++11). In C++17, you'll additionally find the usual convenience helper std::tuple_size_v<some_array_type>.
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.

Comments

5

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:

Comments

5

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; 

1 Comment

This should have been flagged as the accepted answer. Not sure though while C++ standard didn't make a static constexpr function for std::array::size.
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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.