Home > Net >  why does ranges::view_interface<T>::size require a move constructor
why does ranges::view_interface<T>::size require a move constructor

Time:11-01

I don't understand where the requirement for moving comes from. I can't find it in forward_range and sized_sentinel... Basic example:


    #include <ranges>
    #include <string>
    #include <iostream>
    
    class vrange: public std::ranges::view_interface<vrange>
    {
        public:
            vrange(std::string &d): data(d){;};
    
            vrange(const vrange &&) = delete;
    
            auto begin() const noexcept { return data.begin(); };
            auto end() const noexcept { return data.end(); };
    
        private:
            std::string data;
    };
    
    int main(){
        std::string h("Hello world");
        vrange r(h);
    
        std::cout << r.size() << std::endl;
        for (const auto &i: r){
            std::cout << i;
            }
        std::cout << std::endl;
        
    
    }

removing the call to r.size(), or defaulting the vrange move constructor and assignment operator makes it compile fine.

compiler message:

/usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g  -v12/bits/ranges_util.h: In instantiation of ‘constexpr _Derived& std::ranges::view_interface<_Derived>::_M_derived() [with _Derived = vrange]’:
/usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g  -v12/bits/ranges_util.h:101:35:   required from ‘constexpr bool std::ranges::view_interface<_Derived>::empty() requires  forward_range<_Derived> [with _Derived = vrange]’
w.cpp:25:12:   required from here
/usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g  -v12/bits/ranges_util.h:70:23: error: static assertion failed
   70 |         static_assert(view<_Derived>);
      |                       ^~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g  -v12/bits/ranges_util.h:70:23: note: constraints not satisfied
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g  -v12/ranges:37:
/usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g  -v12/concepts:136:13:   required for the satisfaction of ‘constructible_from<_Tp, _Tp>’ [with _Tp = vrange]
/usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g  -v12/concepts:150:13:   required for the satisfaction of ‘move_constructible<_Tp>’ [with _Tp = vrange]
/usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g  -v12/concepts:247:13:   required for the satisfaction of ‘movable<_Tp>’ [with _Tp = vrange]
/usr/lib/gcc/x86_64-pc-linux-gnu/12/include/g  -v12/concepts:137:30: note: the expression ‘is_constructible_v<_Tp, _Args ...> [with _Tp = vrange; _Args = {vrange}]’ evaluated to ‘false’
  137 |       = destructible<_Tp> && is_constructible_v<_Tp, _Args...>;

CodePudding user response:

This has nothing to do with size specifically.

view_interface is used to build a type that is a view. Well, the ranges::view concept requires that the type is at least moveable. And view_interface has a very specific requirement on the type given as its template argument:

Before any member of the resulting specialization of view_interface other than special member functions is referenced, D shall be complete, and model both derived_from<view_interface<D>> and view.

Well, your type does not model view because it is not moveable. So you broke the rules, and you therefore get undefined behavior. Which can include compile errors happening if you call certain members but not others.

  • Related