Согласно Как заставить конструктор принимать все типы итераторов? Я пытаюсь заставить функцию принимать итераторы из разных типов контейнеров. В отличие от этого вопроса, я хочу, чтобы в этих контейнерах были только элементы определенного типа. Однако, если я использую следующий код, я теряю возможность управлять типом элемента:
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");
}
}
Здесь static_assert
— не очень плохое решение, потому что ошибка, которую я получаю, совсем не тривиальна для понимания.
Давайте представим мой main
как
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;
}
Вы можете переместить требование is_arithmetic
в отдельное требование concept
, которое ниже называется iterator_over_arithmetic_type
:
template <class ITER>
concept iterator_over_arithmetic_type =
std::input_iterator<ITER> &&
std::is_arithmetic_v<std::iter_value_t<ITER>>;
template <iterator_over_arithmetic_type ITER>
void f(ITER start, ITER end) {
for (auto it = start; it != end; ++it) {
}
}
Вы можете ограничить value_type
итератора (std::iter_value_t
) арифметическим типом с помощью
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)
{
// ...
}
}
В C++20 тип, возвращаемый end()
диапазона (т. е. тип дозорного), может отличаться от его begin()
, поэтому вам также может потребоваться
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)
{
// ...
}
}
std::is_arithmetic<decltype(*it)>::value
почти наверняка не то, что вам нужно. Обычноdecltype(*it)
будет ссылочным типом, который не может быть арифметическим. Кроме того,*it
может даже не быть ссылкой на тип значения. Это может быть, например. тип прокси, который преобразуется только в тип значения. Вам нужно выяснить, хотите ли вы проверитьstd::iter_value_t
илиstd::iter_reference_t
.