# For element in range in C++

While I was a teacher assistant and during my time helping new employees move from Python to C++, I have gotten one question often.
Why can I not do a for loop like this `for elm in range(0, 10)`

and you know what that is actually a fair question.
In particular for arithmetic types… but what if you could part of the way?

Well first, let us look at a concept to define a type that must be an arithmetic type.
This can be done fairly easy like this `template<typename NumericType> concept Numeric = std::is_arithmetic<NumericType>::value;`

.
Basically what this does is to create a type that must be numeric. I will show a little later what happens if you use one that is not.

Next let us generate the range, here I will use `std::vector`

as my range container.
This can be done very simply with the function below.
This assume that `start`

is smaller than `end`

, otherwise it will not work.

```
template <Numeric T> constexpr std::vector<T> range(T start, T end)
{
T size = end - start;
std::vector<T> data(size);
for (T i = 0; i < size; ++i)
{
data.at(i) = start + i;
}
return data;
}
```

Now let us test it.
For this we will make a `print_range`

function which takes `start`

and `end`

and calls `range`

and prints the resulting “range”.
Again we use the `Numeric`

template type constrained to be a arithmetic type.

```
template <Numeric T> void print_range(T start, T end)
{
std::cout << "[";
for (const auto val : range(start, end))
{
std::cout << " " << std::to_string(val);
}
std::cout << " ]\n";
}
```

Finally our main function, where we test with `size_t`

, `int`

, and `float`

.

```
int main(void)
{
print_range(static_cast<size_t>(1), static_cast<size_t>(10));
print_range(1, 10);
print_range(1.0, 10.0);
}
```

The expected result is:

```
[ 1 2 3 4 5 6 7 8 9 ]
[ 1 2 3 4 5 6 7 8 9 ]
[ 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 9.000000 ]
```

The program should be compiled with `clang++ -std=c++20`

or `g++ -std=c++20`

.
The full program is listed below:

```
#include <vector>
#include <concepts>
#include <iostream>
#include <string>
template<typename NumericType> concept Numeric = std::is_arithmetic<NumericType>::value;
template <Numeric T> constexpr std::vector<T> range(T start, T end)
{
T size = end - start;
std::vector<T> data(size);
for (T i = 0; i < size; ++i)
{
data.at(i) = start + i;
}
return data;
}
template <Numeric T> void print_range(T start, T end)
{
std::cout << "[";
for (const auto val : range(start, end))
{
std::cout << " " << std::to_string(val);
}
std::cout << " ]\n";
}
int main(void)
{
print_range(static_cast<size_t>(1), static_cast<size_t>(10));
print_range(1, 10);
print_range(1.0, 10.0);
}
```

Now let us say we had called `print_range`

with `"a"`

as `start`

and `"z"`

as `end`

.
Well then you would get the following compilation error:

```
main.cpp:34:5: error: no matching function for call to 'print_range'
34 | print_range("a", "z");
| ^~~~~~~~~~~
main.cpp:19:27: note: candidate template ignored: constraints not satisfied [with T = const char *]
19 | template <Numeric T> void print_range(T start, T end)
| ^
main.cpp:19:11: note: because 'const char *' does not satisfy 'Numeric'
19 | template <Numeric T> void print_range(T start, T end)
| ^
main.cpp:6:50: note: because 'std::is_arithmetic<const char *>::value' evaluated to false
6 | template<typename NumericType> concept Numeric = std::is_arithmetic<NumericType>::value;
| ^
1 error generated.
```

Some final remarks. First,this can be made MUCH prettier (which I may show in a later post). Secondly, this is not very optimised and only serves as inspiration. Finally, play around with it.

*./Lars*