Вчера мое утро началось с того, что под Linux-ом компилятор GCC 13 отказался компилировать код вроде вот такого (это не реальный код, а минимизированая версия на которой проблема воспроизводится):
|
template< typename T, typename Range > [[nodiscard]] T make_from( const Range & r ) { return T{ r.begin(), r.end() }; } int main() { std::string src{ "Hello, World" }; auto v = make_from< values_container >( std::ranges::views::iota( 0u, src.size()) ); std::cout << v.front() << " - " << v.back() << std::endl; } |
Изначально код был написан под другую платформу с более свежим С++ным компилятором, поэтому там make_from был реализован иначе, проблем с компиляцией не было. А вот под уже довольно древним по современным меркам GCC возникли проблемы: компилятор не видел у values_container конструктора, который бы получал два итератора.
Конкретно в моем случае в качестве values_container был folly::fbvector, но это не суть. Вполне мог бы быть и std::vector, проблема была бы точно такой же.
Ошибка несколько обескуражила, т.к. я точно знал, что у values_container есть конструктор, принимающий итераторы first и last.
Но с этим-то удалось разобраться достаточно быстро: first и last должны быть одного типа. А в моем случае объект-рэндж, возвращенный вызовом iota, имел разные типы для begin() и для end(). Соответственно, раз типы итераторов разные, то и компилятор не может найти подходящий конструктор у values_container.
Ну OK, раз типы у итераторов разные, то можно к этой ситуации приспособить реализацию make_from. Например, написать ее так: