Can I list-initialize a vector of move-only type?

前端 未结 5 1123
感情败类
感情败类 2020-11-22 08:30

If I pass the following code through my GCC 4.7 snapshot, it tries to copy the unique_ptrs into the vector.

#include 
#include <         


        
5条回答
  •  一向
    一向 (楼主)
    2020-11-22 08:38

    Edit: Since @Johannes doesn't seem to want to post the best solution as an answer, I'll just do it.

    #include 
    #include 
    #include 
    
    int main(){
      using move_only = std::unique_ptr;
      move_only init[] = { move_only(), move_only(), move_only() };
      std::vector v{std::make_move_iterator(std::begin(init)),
          std::make_move_iterator(std::end(init))};
    }
    

    The iterators returned by std::make_move_iterator will move the pointed-to element when being dereferenced.


    Original answer: We're gonna utilize a little helper type here:

    #include 
    #include 
    
    template
    struct rref_wrapper
    { // CAUTION - very volatile, use with care
      explicit rref_wrapper(T&& v)
        : _val(std::move(v)) {}
    
      explicit operator T() const{
        return T{ std::move(_val) };
      }
    
    private:
      T&& _val;
    };
    
    // only usable on temporaries
    template
    typename std::enable_if<
      !std::is_lvalue_reference::value,
      rref_wrapper
    >::type rref(T&& v){
      return rref_wrapper(std::move(v));
    }
    
    // lvalue reference can go away
    template
    void rref(T&) = delete;
    

    Sadly, the straight-forward code here won't work:

    std::vector v{ rref(move_only()), rref(move_only()), rref(move_only()) };
    

    Since the standard, for whatever reason, doesn't define a converting copy constructor like this:

    // in class initializer_list
    template
    initializer_list(initializer_list const& other);
    

    The initializer_list> created by the brace-init-list ({...}) won't convert to the initializer_list that the vector takes. So we need a two-step initialization here:

    std::initializer_list> il{ rref(move_only()),
                                                       rref(move_only()),
                                                       rref(move_only()) };
    std::vector v(il.begin(), il.end());
    

提交回复
热议问题