Why no emplacement iterators in C++11 or C++14?

前端 未结 2 1845
梦如初夏
梦如初夏 2020-12-08 00:34

C++98 has front_inserter, back_inserter, and inserter, but there don\'t seem to be any emplacement versions of these in C++11 or draft

相关标签:
2条回答
  • 2020-12-08 00:53

    Is there any technical reason we couldn't have front_emplacer, back_emplacer, and emplacer?

    No, there is no technical reason. As proof, here is a complete implementation of back_emplacer with a demo of your Use Case 1...

    #include <iterator>
    #include <vector>
    #include <iostream>
    
    template<class Container>
    class back_emplace_iterator : public std::iterator< std::output_iterator_tag,
                                                       void, void, void, void >
    {
    protected:
        Container* container;
    public:
        typedef Container container_type;
    
        explicit back_emplace_iterator(Container& x) : container(&x) {}
    
        template<class T>
        back_emplace_iterator<Container>&
        operator=(T&& t)
        {
            container->emplace_back(std::forward<T>(t));
            return *this;
        }
    
        back_emplace_iterator& operator*() { return *this; }
        back_emplace_iterator& operator++() { return *this; }
        back_emplace_iterator& operator++(int) { return *this; }
    };
    
    template< class Container >
    inline back_emplace_iterator<Container>
    back_emplacer( Container& c )
    {
        return back_emplace_iterator<Container>(c);
    }
    
    struct Demo
    {
        int i;
        Demo(int i) : i(i) {}
    };
    
    int main()
    {
        std::vector<int> x = {1,2,3,4,5};
    
        std::vector<Demo> y;
    
        std::copy(x.begin(), x.end(), back_emplacer(y));
    
        for (auto d : y)
            std::cout << d.i << std::endl;
    }
    

    Possible Known Issue: Does the universal reference of operator= hide an implicitly generated copy/move operator=? If so these need to be explicitly defined in a way that beats the universal reference in overload resolution.

    0 讨论(0)
  • 2020-12-08 00:54

    Your main use case is already covered by inserter, back_inserter and front_inserter. There is already a value_type && overload of operator= that will move into the container. The only thing emplacer could do over inserter is call explicit constructors.

    Compare the common overloads of container::insert, container::push_back and container::push_front to container::emplace, container::emplace_back and container::emplace_front

    iterator insert( const_iterator pos, const value_type & value );
    iterator insert( const_iterator pos, value_type && value );
    
    template< class... Args > 
    iterator emplace( const_iterator pos, Args&&... args );
    
    void push_back( const value_type & value );
    void push_back( value_type && value );
    
    template< class... Args >
    void emplace_back( Args&&... args );
    
    void push_front( const value_type & value );
    void push_front( value_type && value );
    
    template< class... Args >
    void emplace_front( Args&&... args );
    

    Each of the emplace variants takes a pack of arguments with which to construct the value. operator = takes exactly one argument. You could write an emplacer that took a tuple of arguments.

    template<class Container>
    class back_emplace_iterator : public std::iterator< std::output_iterator_tag,
                                                       void, void, void, void >
    {
    protected:
        Container* container;
    public:
        typedef Container container_type;
    
        explicit back_emplace_iterator(Container& x) : container(&x) {}
    
        template<typename ... Args>
        back_emplace_iterator<Container>&
        operator=(std::tuple<Args&&...> args)
        {
            std::apply(Container::emplace_back, std::tuple_cat(std::tie(*container), std::forward<std::tuple<Args&&...>>(args)));
            return *this;
        }
    
        back_emplace_iterator& operator*() { return *this; }
        back_emplace_iterator& operator++() { return *this; }
        back_emplace_iterator& operator++(int) { return *this; }
    };
    
    0 讨论(0)
提交回复
热议问题