【发布时间】:2014-11-06 08:16:03
【问题描述】:
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 类型的值:
要求:
T是CopyInsertable到X§23.2.1 [container.requirements.general]
我对此的理解:如果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
TisCopyInsertableintoX意味着除了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 [unique.ptr]
并且由于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;模板特化
is_constructible<T, Args...>的谓词条件当且仅当以下变量定义对于某个发明变量t的格式正确:
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++,否则我会对其进行测试。
【问题讨论】:
-
我认为标准并不能保证这个复制构造函数以可以测试的方式无效。但至少作为 QoI,我认为 libstdc++ PR 会很好。 libc++ (clang) 以同样的方式失败。
-
容器要求在 Requires 子句中说明。打破 Requires 子句是 UB;它不保证错误,更不用说可以通过类型特征测试的错误了。
is_*_constructible特征只考虑“变量初始化的直接上下文的有效性”——基本上,匹配 ctor 签名的存在。它不考虑ctor在实例化时是否会编译。 -
在 MSVS 2013(12.0.30723.00 更新 3)中,即使这样也失败了:
static_assert(!std::is_copy_constructible<std::unique_ptr<int>>::value, "Copyable"); -
@AntonSavin 这是他们编译器中的一个已知错误。
标签: c++ gcc g++ language-lawyer c++14