std::unordered_map<T,std::unique_ptr<U>>可复制吗?海湾合作委员会错误?
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
有效,对于某些容器类型X
,它包含类型T
,其中a
是类型为X
的值:
要求:
T
CopyInsertable
X
§23.2.1 [容器.要求.一般]
我对此的理解是:如果T
(在我们的例子中std::pair<const int,std::unique_ptr<int>>
(没有CopyInsertable
到X
(在我们的例子中std::unordered_map<int,std::unique_ptr<int>>
(,那么X u(a)
和X u=a
的格式不正确。
CopyInsertable
T
CopyInsertable
X
意味着,除了T
被MoveInsertable
到X
中之外,以下表达式的格式良好:
allocator_traits<A>::construct(m, p, v)
其计算导致以下后置条件成立:
v
的值保持不变,等效于*p
。
我对此的理解是:std::pair<const int,std::unique_ptr<int>>
不是CopyInsertable
,因为std::unique_ptr<int>
是不可复制的:
从此子句 [...] 中指定的
unique_ptr
模板实例化的类型的每个对象U
既不CopyConstructible
也不CopyAssignable
。§20.8.1 [唯一.PTR]
并且由于 std::pair<const int,std::unique_ptr<int>>
的复制构造函数是默认的:
pair(const pair&) = default;
§20.3.2 [对]
并且由于std::pair<const int,std::unique_ptr<int>>
有一个类型 std::unique_ptr<int>
的成员:
template <class T1, class T2> struct pair {
[...]
T2 second;
§20.3.2 [对]
并且由于当不是CopyConstructible
类型的所有成员时,默认的复制构造函数将被删除:
类
X
的默认复制/移动构造函数定义为已删除,如果 X 具有:[...]
- 类类型
M
(或其数组(的非静态数据成员,无法复制/移动,因为应用于M
相应构造函数的重载分辨率会导致 [...]§12.8 [类副本]
在std::is_copy_constructible
对于可引用的类型
T
,结果与is_constructible<T,const T&>::value
相同, 否则false
.§20.10.4.3 [元.一元.道具]
我对此的理解/解读: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;
专用化
is_constructible<T, Args...>
的谓词条件应满足,当且仅当以下变量定义对于某些发明的变量t
格式良好时:
T t(create<Args>()...);
§20.10.4.3 [元.一元.道具]
我对此的理解是: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++,否则我会对它们进行测试。
您的分析中有两个问题。
首先,违反 Require 子句会导致未定义的行为 (§17.6.4.11 [res.on.required](:
违反函数要求中指定的前提条件: 段落会导致未定义的行为,除非函数的 抛出:段落指定在违反前提条件时抛出异常。
这意味着,如果您尝试使用非 CopyInsertable 元素复制构造unordered_map
,该库可以执行任何它想要的操作。它不一定会导致程序格式不正确(尽管它可能会在复制构造函数实现的深处的某个地方(。
其次,is_constructible
性状执行的测试仅限于直接上下文(§20.10.4.3 [meta.unary.prop]/p7,着重号是加的(:
执行访问检查就像在与
T
和任何无关的上下文中一样 的Args
.只有直接上下文的有效性 考虑变量初始化。[注:评价 初始化可能会导致副作用,例如 类模板专用化和函数模板的实例化 专业化,隐式定义函数的生成,以及 等等。这种副作用不在"直接上下文"中,并且可以 导致程序格式不正确。—尾注 ]
换句话说,这基本上只考虑是否存在匹配、可访问且未删除的构造函数签名,而不是实例化构造函数是否会产生格式正确的代码。
该标准必须指定容器的复制构造函数,内容类似于"如果T
不能 CopyInsertable to X
,则此构造函数不得参与重载解析",以保证 is_copy_constructible
特征的行为方式。标准中没有这样的规范。
正如Marc Glisse在评论中所写的那样,虽然这不是标准强制要求的,但它可以被认为是实现质量问题,因此错误报告是合理的。
编辑:我突然想到,从非CopyInsertable
元素的重载解析中删除复制构造函数的要求可能无法实现,因为该属性是根据对allocator_traits<A>::construct(m, p, v)
格式正确并具有所需语义的调用指定的。我不相信SFINAE可以确定allocator_traits<A>::construct()
呼吁的身体的良好形成。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 是std :: set&lt; std :: future&gt;不可能存在
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- 使用 std::vector<boost::shared_ptr<Base_Class>> 或 boost::p tr_vector 的性能注意事项是什么<Base>
- std::map<std::set, double> AND std:<long>map< std::p air<long, long>, double>
- 如何获取std::vector<DMatch>