簡體   English   中英

的std :: unordered_map <T,std::unique_ptr<U> &gt;可復制? GCC錯誤?

[英]std::unordered_map<T,std::unique_ptr<U>> copyable? GCC bug?

g++ --version產生:

g++.exe (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 4.9.1
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

程序:

#include <memory>
#include <type_traits>
#include <unordered_map>

static_assert(!std::is_copy_constructible<std::unordered_map<int,std::unique_ptr<int>>>::value,"Copyable");

int main () {   }

編譯結果:

.\unorderedmapcopyable.cpp:5:1: error: static assertion failed: Copyable
 static_assert(!std::is_copy_constructible<std::unordered_map<int,std::unique_ptr<int>>>::value,"Copyable");
 ^

相關標准:

關於容器可復制

對於語句X u(a)X u=a有效,對於某些包含類型T容器類型X ,其中a是類型X的值:

要求: TCopyInsertableX

§23.2.1[container.requirements.general]

我對此的理解:如果T (在我們的例子中是std::pair<const int,std::unique_ptr<int>> )不是CopyInsertableX (在我們的例子中是std::unordered_map<int,std::unique_ptr<int>> ),然后X u(a)X u=a的格式不正確。

CopyInsertable

TCopyInsertableX意味着,除了TMoveInsertableX ,下面的表達式是格式良好的:

allocator_traits<A>::construct(m, p, v)

並且它的評估導致以下后置條件保持: v的值不變並等於*p

我對此的理解: std::pair<const int,std::unique_ptr<int>>不是CopyInsertable ,因為std::unique_ptr<int>不可復制:

CopyConstructible條款[...]中指定的unique_ptr模板實例化的類型U每個對象不是CopyConstructible也不是CopyAssignable

§20.8.1[unique.ptr]

並且由於std::pair<const int,std::unique_ptr<int>>的復制構造std::pair<const int,std::unique_ptr<int>>是默認的:

pair(const pair&) = default;

§20.3.2[pairs.pair]

並且由於std::pair<const int,std::unique_ptr<int>>的成員具有std::unique_ptr<int>類型的成員:

template <class T1, class T2> struct pair {

[...]

T2 second;

§20.3.2[pairs.pair]

並且由於在不是類型的所有成員都是CopyConstructible的情況下刪除了默認的復制構造函數:

如果X具有以下內容,則將類X默認復制/移動構造函數定義為已刪除:

[...]

  • 類型M (或其數組)的非靜態數據成員,由於應用於M的相應構造函數的重載解析,無法復制/移動,導致[...]刪除的函數[...] ]

§12.8[class.copy]

std::is_copy_constructible

對於可引用類型T ,與is_constructible<T,const T&>::value結果相同,否則為false

§20.10.4.3[meta.unary.prop]

我對此的理解/解讀: std::is_copy_constructible<std::unordered_map<int,std::unique_ptr<int>>std::is_constructible<std::unordered_map<int,std::unique_ptr<int>,std::unordered_map<int,std::unique_ptr<int> &>

std::is_constructible

給出以下函數原型:

template <class T> add_rvalue_reference_t<T> create() noexcept;

當且僅當以下變量定義適用於某些發明變量t ,才能滿足模板特化的謂詞條件is_constructible<T, Args...>

T t(create<Args>()...);

§20.10.4.3[meta.unary.prop]

我對此的理解: std::is_constructible<std::unordered_map<int,std::unique_ptr<int>>,std::unordered_map<int,std::unique_ptr<int> &>應該是std::false_type ,不是std::true_type ,因為X u(a)格式不正確。

我的問題

是否應接受上述代碼? 這是一個GCC / libstdc ++錯誤,還是我缺少標准中的某些內容?

我目前無法訪問Clang或MSVC ++,否則我會對它們進行測試。

您的分析中存在兩個問題。

首先,違反Requires子句會導致未定義的行為(第17.6.4.11節[res.on.required]):

違反函數的Requires:段中指定的前提條件會導致未定義的行為,除非函數的Throws: paragraph指定在違反前提條件時拋出異常。

這意味着如果您嘗試使用非CopyInsertable元素復制構造unordered_map ,則庫可以執行任何操作。 它不一定會導致程序格式不正確(盡管它可能會在復制構造函數的實現中深處)。

其次, is_constructible trait執行的測試僅限於直接上下文(§20.10.4.3[meta.unary.prop] / p7,強調添加):

執行訪問檢查就像在與T和任何Args無關的上下文中一樣。 僅考慮變量初始化的直接上下文的有效性。 [ 注意 :初始化的評估可能會導致副作用,例如類模板特化和函數模板特化的實例化,隱式定義函數的生成等等。 這種副作用不在“直接背景”中,並且可能導致程序形成不良。 - 結束說明 ]

換句話說,這基本上只考慮是否存在匹配的,可訪問的和未刪除的構造函數簽名,而不是實例化構造函數將導致格式良好的代碼。

標准必須指定容器的復制構造函數,其中包含“如果T不是CopyInsertable進入X則此構造函數不應參與重載解析”以保證is_copy_constructible特征的行為符合您的is_copy_constructible 標准中沒有這樣的規范。

正如Marc Glisse在評論中寫道,雖然這不是標准規定的,但它可以被認為是一個實施質量問題,因此錯誤報告是合理的。


編輯:我想到,從非CopyInsertable元素的重載解析中刪除復制構造函數的要求可能無法實現,因為該屬性是根據對allocator_traits<A>::construct(m, p, v)格式良好並具有所需的語義。 我不相信SFINAE可以確定對allocator_traits<A>::construct()的調用主體的格式良好。

暫無
暫無

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

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