As per How to make constructor accept all type of iterators? I am trying to have a function accept iterators from different container types. Unlike that question, i want those containers to have only the specific type of elements. However, if i use the following code, i lose the ability to control the element type:
template<std::input_iterator ITER>
void f(ITER start, ITER end)
{
for(auto it=start; it!=end; ++it)
{
static_assert(std::is_arithmetic<decltype(*it)>::value, "Not arithmetic");
}
}
In here static_assert
is not a very poor solution, because the error that i get is anything, but trivial to understand.
Let's imagine my main
as
int main()
{
std::vector<int> v_good{{1, 2, 3, 4, 5}};
std::vector<std::string> v_bad{{std::string("hello"), std::string("world")}};
std::list<int> l_good{{1, 2, 3, 4, 5}};
f(v_good.begin(), v_good.end());
f(l_good.begin(), l_good.end());
f(v_bad.begin(), v_bad.end()); // at this point i want to get a compilation error
return 0;
}
You can constrain the value_type
of the iterator (std::iter_value_t
) to be an arithmetic type by
template<std::input_iterator ITER>
requires std::is_arithmetic_v<std::iter_value_t<ITER>>
void f(ITER start, ITER end)
{
for (auto it=start; it!=end; ++it)
{
// ...
}
}
In C++20, the type returned by a range's end()
(i.e., the sentinel type) can be different from its begin()
, so you may also need
template<std::input_iterator ITER, std::sentinel_for<ITER> SENT>
requires std::is_arithmetic_v<std::iter_value_t<ITER>>
void f(ITER start, SENT end)
{
for(auto it=start; it!=end; ++it)
{
// ...
}
}