0

I was trying out some C++20 when I stumbled upon a rather strange (at least to me) situation. I was expecting the following code to not work with one of my examples (I've specified the expected behavior with comments), but it did work, and I want to know why. Here's the code snippet:

#include <iostream>
#include <span>

using namespace std;

struct simpleType
{
    simpleType(const int id) : id(id) {}

    int id;
};

template <typename IterableType>
void print(const IterableType& sequenceToPrint)
{
    cout << "[ ";

    for(const auto& element : sequenceToPrint)
    {
        cout << element.id << " ";
    }

    cout << "]" << endl;
}

void test()
{
    simpleType arr [] {1,2,3,4,5};
    span arrSpan {arr};

    // This should work
    print(arrSpan); // prints [ 1 2 3 4 5]
    // This should not
    print(arr); // prints [ 1 2 3 4 5 ] as well
}

int main()
{
    test();
}

I wasn't expecting it to work in both situations because, from my understanding, my templated print function should only work with iterable types because of the range based for loop. What am I missing?

  • 1
    about `print(arr)`, [std::begin](https://en.cppreference.com/w/cpp/iterator/begin) (constructor 2) and std::end are also considered, and valid for "C" style arrays. And thus a range base for loop works for "C" style arrays too – Pepijn Kramer Aug 12 '23 at 19:24
  • Hint: **Iterable** is not a C++ term(C# or else maybe). **`std::ranges::range`** is the `concept` to constrain your template parameter; thus **range** maybe the correct term to describe it. – Red.Wave Aug 13 '23 at 09:58

2 Answers2

2

the first loop on an array works because c++ can produce a range based for loop for arrays if it knows its size at compile time and the template is deduced as <simpleType[5]>

the template will fail if you are passing simpleType* as the array size is not known at compile time.

std::span can also be constructed from an array if the array size is known at compile time, and std::span provides the needed begin and end methods that return an iterator type which are needed for a range based for loop.

Ahmed AEK
  • 8,584
  • 2
  • 7
  • 23
0

For this

print(arrSpan)

the implicit instantiation of template would be:

void print<std::span<simpleType, 5> >(const std::span<simpleType, 5>& sequenceToPrint)

and for this

print(arr)

the implicit instantiation of template would be:

void print<simpleType[5]>(const simpleType (&sequenceToPrint)[5])

Both are iterable.

H.S.
  • 11,654
  • 2
  • 15
  • 32