簡體   English   中英

將列表初始化對插入到std :: map中

[英]Insert list-initialized pair into std::map

我正在嘗試將僅移動類型插入地圖。 我有以下代碼:

#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;
}

發生的情況是使用VisualC ++第1,2和3行進行編譯。 在clang和gcc中,只有1和2編譯,第3行給出錯誤(使用已刪除的副本構造函數)。

問題:哪種編譯器正確,為什么?

在這里嘗試: rextester

std::map::insert具有(除其他以外)以下重載:

// 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 );

第一次重載顯然不能與僅移動類型一起使用。 但是第二個重載雖然在C ++ 11中可用,但在這里不適用於大括號,因為模板參數推導不會與大括號一起發生(至少在C ++ 11中,不確定更高版本的標准)。

insert的第一個和第二個調用都可以在C ++ 11或更高版本中使用,因為編譯器知道類型,但第三個失敗。

C ++ 17添加了另一個重載,該重載適用於花括號和僅移動類型。 現在,為什么它可以與某些編譯器一起使用,而不能與其他編譯器一起使用,這很可能是由於C ++ 17支持級別或編譯器標志的差異。

更新:只是為了使它變得顯而易見:使用括號是指僅使用括號(聚合初始化或隱式構造函數調用),即insert({k,v}) ,而不是insert(pair<K,V>{k,v}) 在后一種情況下,類型是已知的,甚至在C ++ 11中也可以選擇模板化重載。

我已經使用g ++ 7.3測試了您的代碼,並且編譯時沒有錯誤!

使用clang ++ 5.0.1不會編譯。

我認為您正在使用c ++ 20的功能,因此尚未在所有編譯器上都提供支持。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM