Search code examples
c++c++11movestd-pair

Move a pair into vector


I have this function template:

template<typename Collection, typename T>
void insertColElement(Collection col, const T& element, std::true_type)
{
    col.insert(col.end(), std::move(element));
}

It is called if T is move-constructable. Now I want to call this function with Collection = std::vector<..> and T = std::pair<std::unique_ptr<..>, bool>, but the compiler complains about the deleted copy constructor of unique_ptr and pair. I already tried to use emplace and move first and second seperately, but the compiler still wants to call the copy constructor.

Edit:

Here are all relevant code snippets:

template<typename Collection, typename T>
void insertColElement(Collection col, T&& element, std::true_type)
{
    col.insert(col.end(), std::forward<T>(element));
}



template<typename Collection, typename T>
void insertColElement(Collection col, T& element, std::false_type)
{
    static_assert(std::is_copy_constructible<T>::value,
        "Serialization: Collection type is neither copy nor move constructable");

    col.insert(col.end(), element);
}


template<typename Archive, typename Collection>
inline void loadCollection(Archive& ar, Collection& col)
{
    int size;
    ar >> size;

    for(int i = 0; i < size; i++) {
        typename Collection::value_type element;
        ar >> element;

        insertColElement(col, std::move(element), 
            typename std::is_move_constructible<typename Collection::value_type>::type());
    }
}

These functions are part of a small serialization module I am working at. loadCollection is used to load a container from an Archiv. The call that causes the issues looks like this:

IStreamArchive a(filestream);
std::vector<std::pair<std::unique_ptr<Scope>, bool>> vec;
a << vec;

Solution

  • You can't move-from something that is const, so you end up with the copy constructor even though you wrote move() (since move is just a cast, you cast element to a const T&&. There is no const T&& constructor, and the T&& constructor doesn't match, so the next best match is the const T& constructor). That's the problem.

    You should instead write the following:

    template<typename Collection, typename T>
    void insertColElement(Collection& col, T&& element, std::true_type)
    {
        col.insert(col.end(), std::forward<T>(element));
    }