1

Following an example from Scott Meyer's "Modern C++", I'd exploit std::array size deduction with templates. I'm stumbled trying to compile my myUsage function usage.

#include <array> #include <iostream> template <typename T, std::size_t N> constexpr std::size_t arraySize(T (&) [N]) noexcept { return N; } void scottUsage() { int b[5]; std::array<short, arraySize(b)> c; std::cout << arraySize(b) << " = " << c.size() << "\n"; } template <typename T, std::size_t N> void myUsage(T & arr [N]) { for (auto i=0; i<arraySize(arr); i++) std::cout << arr[i] << "\t"; } int main() { scottUsage(); int a[7]; myUsage(a); } 

So two questions arise:

  1. (side question) What's (&) for? Removing would trigger error: creating array of references, which it seems to be forbidden
  2. What's wrong with myUsage signature?
6
  • 3
    Shouldn't it be myUsage(T (&arr) [N])? The parentheses are important to make it a reference to an array (instead of an array of references). Commented Jan 2, 2020 at 7:23
  • For sure, thank you both. Please provide comments as answers (maybe with few explanation of (&varname) uncommon syntax, and I'll be glad to mark as solved Commented Jan 2, 2020 at 7:29
  • 1
    Also, a in main() is an array of uninitialised int. Printing the elements in myUsage() - once you fix the typo with the argument - therefore causes undefined behaviour. Commented Jan 2, 2020 at 7:31
  • Really Peter? I thought I was just reading garbage data. Anyway that was for example sake Commented Jan 2, 2020 at 7:40
  • @PatrizioBertoni It's best to keep examples as simple as possible so that you don't accidentally introduce bugs that were originally not relevant to your question. In other words, examples should be minimal. see minimal reproducible example. Commented Jan 2, 2020 at 7:42

2 Answers 2

6
  1. What's (&) for?

It makes the argument a reference. If it wasn't a reference, then it would be an array. But function arguments are not allowed to be arrays, and such declarations are adjusted to be a pointer to an element of the array. Since this type does not carry information about size of the array, it is not useful to the size deduction.

Removing would trigger error: creating array of references, which it seems to be forbidden

void myUsage(T & arr [N]) 

Indeed, the parentheses are mandatory. They are needed to signify that the reference applies to the array and not the element type of the array. T&[N] is an array of references (which is not allowed) while T(&)[N] is a reference to an array.

  1. What's wrong with myUsage signature?

Arrays of references are not allowed.

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

Comments

4

myUsage() needs to use T (&arr) [N].

template <typename T, std::size_t N> void myUsage(T (&arr) [N]) 

The parentheses tell the compiler that the reference applies to the array itself and not to the element type of the array.

Also, both arraySize() and myUsage() should take a reference to const data:

template <typename T, std::size_t N> constexpr std::size_t arraySize(const T (&) [N]) noexcept ... template <typename T, std::size_t N> void myUsage(const T (&arr) [N]) 

BTW, arraySize() is not needed from C++17 onward, use std::size() instead:

#include <array> #include <iostream> #include <iterator> void scottUsage() { int b[5]; std::array<short, std::size(b)> c; std::cout << std::size(b) << " = " << c.size() << "\n"; } template <typename T, std::size_t N> void myUsage(const T (&arr) [N]) { for (auto i = 0; i < std::size(arr); ++i) std::cout << arr[i] << "\t"; /* better: for (const T &value : arr) std::cout << value << "\t"; */ } int main() { scottUsage(); int a[7]; myUsage(a); } 

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.