1

I wondered if I could auto deduce the size of an array, which is passed as a template parameter, without (explicitly) passing its size.

The following code both compiles warning-less on g++ 4.8 and clang++ 3.3 (using -std=c++11 -Wall).

#include <iostream> template<const int* arr> struct array_container { static constexpr int val = arr[1]; array_container() { std::cout << val << std::endl; } // static constexpr int arr_size = ??; }; constexpr int one[] = { 1 }; constexpr int two[] = { 1, 2 }; int main() { // array_container<one> array_one; array_container<two> array_two; // (void) array_one; (void) array_two; return 0; } 

However, if I remove the two comment signs in main(), I get an out of bound error with both compilers.

Now, this is cool. Somehow the compiler knows the size of the array, though the type of const int* arr is a pointer. Is there any way to get the size of arr, e.g. to complete my comment in array_container?

Of course, you are not allowed to

  • Use any macros
  • Store the size in arr (e.g. passing an std::array as template parameter: constexpr std::array<int, 1> one = { 1 }, or using an end marker like '\0' in strings)
  • Use an additional template parameter for the size that can not be auto deduced (array_container<1, one> array_one).
5
  • Is it really the compiler that give you an error, or is it a runtime-error (crash)? Commented Mar 15, 2014 at 11:44
  • @JoachimPileborg the compiler, indeed. I can not even compile this program. Commented Mar 15, 2014 at 11:48
  • What is it that you are trying to do? Commented Mar 15, 2014 at 11:50
  • @Jefffrey edited: I want to auto-deduce the size by passing only the array, not (explicitly) the array size. Commented Mar 15, 2014 at 11:53
  • I don't suppose array_container<decltype(arr_a), arr_a>::size is acceptable? :p Commented Mar 15, 2014 at 13:37

4 Answers 4

1

Maybe std::extent template from <type_traits> header of C++11 standard library is what you want:

#include <iostream> #include <type_traits> constexpr int one[] = { 1 }; constexpr int two[] = { 1, 2 }; int main() { std::cout << std::extent<decltype(one)>::value << std::endl; std::cout << std::extent<decltype(two)>::value << std::endl; return 0; } 

Output:

1 2 
Sign up to request clarification or add additional context in comments.

2 Comments

The question asked if it was possible to "auto deduce the size of an array, which is passed as a template parameter". My example code shows it: You should have passed the array to a (self written) struct and read the size there. You don't pass the array to a struct. So your answer is off-topic.
@Johannes OK, I understand know. Both of my solution and badair's one are compile-time and solve the problem of finding the size of the array. But you want to pass an array just as a template parameter. Why do you want to do it? I think your solution is overcomplicated to all possible reasonable applications.
1
template<size_t size> constexpr size_t arraySize ( const int ( &arrayRef ) [size] ) { return size; } int main(){ int A[1]; int B[2]; cout << arraySize(A) << arraySize(B); return 0; } 

I believe something like this is what you're looking for, using array references. The syntax for declaring an array reference looks kind of like the syntax for a function pointer. This function template accepts an array reference named arrayRef, which prevents array-to-pointer decay so that compile-time info about array size is preserved. As you can see, the template argument is implicit to the compiler. Note that this can only work when the size can be deduced at compile time. Interestingly, this should still work without naming arrayRef at all. To make the above template more useful, you can add a template parameter to deduce the type of the array as well. I left it out for clarity.

3 Comments

First: Don't use int for sizes (Don't use signed integers). Use std::size_t instead. Also, you should make the function constexpr to suggest the compiler to compute the array size at compile time.
arrayRef may be const: arraySize(const int (&arrayRef)[size])
You should have passed the array as template parameter to a user defined struct (like my example code in the question shows). You, however, passed the array as a function parameter.
0

Probably not, as SFINAE only happens in the immediate context, while that error comes from the requirement that UB in constexpr lead to a compile time error, which I think is not immediate. You could try a recursive SFINAE that stops on the UB, but even if it worked you would have to both check the standard and hope it does not change (as it is rather obscure and new).

The easy way is to ise s function to deduce the array size, have to explicitly pass it to the type, then store it in an auto. Probably not what you want.

There are proposals to allow type parameters to be deduced from value parameters, so you could wait for those instead.

Not a solid answer, more of an extended comment, so marked community wiki.

Comments

0

It is indeed possible. I found a solution using SFINAE. What it basically does is produce a substitution error if the index is out of bound (line 3 in this example):

template<class C> static yes& sfinae(typename val_to_type< decltype(*C::cont::data), *(C::cont::data + C::pos)>::type ); template<class C> static no& sfinae(C ); 

The full source code is on github.

There are only two disadvantages:

  1. You have to specify the type of the array (this can not be avoided)
  2. It only works with g++ 4.8.1 and clang 3.3. g++ fails for empty strings (with a compiler bug). If someone can test for other compilers, that would be appreciated.

1 Comment

Why this solution is better than mine or @badair's?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.