简体   繁体   中英

Insert list-initialized pair into std::map

I'm trying to insert a move-only type into a map. I have the following piece of code:

#include <map>

class Moveable
{
public:
    Moveable() = default;
    Moveable(const Moveable&) = delete;
    Moveable(Moveable&&) = default;
    Moveable& operator=(const Moveable&) = delete;
    Moveable& operator=(Moveable&&) = default;
};

int main() {
    std::map<int,Moveable> my_map;
    Moveable my_moveable_1, my_moveable_2, my_moveable_3;
    my_map.insert(std::pair<int,Moveable>{1, std::move(my_moveable_1)}); // (1)
    my_map.insert(std::make_pair(2, std::move(my_moveable_2)));          // (2)
    my_map.insert({3, std::move(my_moveable_3)});                        // (3)

    return 0;
}

What happens is that using VisualC++ lines 1,2 and 3 compile. In clang and gcc, only 1 and 2 compile and line 3 gives an error (use of deleted copy constructor).

Question: Which compiler is right and why?

Try it here: rextester

std::map::insert has (among others) the following overloads:

// 1.
std::pair<iterator,bool> insert( const value_type& value );

// 2. (since C++11)
template< class P >
std::pair<iterator,bool> insert( P&& value );

// 3. (since C++17)
std::pair<iterator,bool> insert( value_type&& value );

The first overload obviously cannot be used with move-only types. But the second overload, while available in C++11, does not work with braces here because template argument deduction does not occur with braces (at least in C++11, not sure about later standards).

Both your first and second call to insert work in C++11 or later because the compiler knows the type, but the third fails.

C++17 adds another overload that works with braces and move-only types. Now as for why it works with certain compilers and not others, this is most likely due to diffences in the level of C++17 support, or compiler flags.

UPDATE: Just to make it painfully obvious: With using braces I mean using braces only (aggregate initialization or implicit constructor call), ie insert({k,v}) , not insert(pair<K,V>{k,v}) . In the latter case, the type is known and the templated overload can be selected even in C++11.

I've tested your code with with g++ 7.3 and it compiles without error!

With clang++ 5.0.1 it doesn't compile.

I think that you are using a feature of the c++20 so the support is not yet ready on all compilers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM