vector.resize(n)
格式良好的要求 (23.3.6.3:10)T
应该是CopyInsertable
,即以下内容应该是格式良好的 (23.2.1:13):
allocator_traits<A>::construct(m, p, v);
其中A
是向量的分配器类型,m
是分配器,p
是类型T *
,v
是类型T
。
正如您从 20.6.8.2:5 中发现的那样,这在一般情况下对数组类型无效,因为它等效于调用
::new(static_cast<void *>(p))block(v);
这对数组类型无效(数组不能用括号初始化)。
实际上,您是正确的 g++ 有一个错误;CopyInsertable
通过提供适当的分配器应该总是可以解决这个问题,但是 g++ 不允许这样做:
#include <vector>
template<typename T, int n> struct ArrayAllocator: std::allocator<T[n]> {
void construct(T (*p)[n], T (&v)[n]) {
for (int i = 0; i < n; ++i)
::new(static_cast<void *>(p + i)) T{v[i]};
}
};
int main() {
std::vector<int[4], ArrayAllocator<int, 4>> c;
c.resize(100); // fails
typedef ArrayAllocator<int, 4> A;
A m;
int (*p)[4] = 0, v[4];
std::allocator_traits<A>::construct(m, p, v); // works
}
另一个错误在于标准本身。20.9.4.3:3 指定std::is_default_constructible<T>
为等效于std::is_constructible<T>
,其中 20.9.4.3:6 指定std::is_constructible<T, Args...>
为 上的良构性标准T t(std::declval<Args>()...)
,这对数组类型有效(正如@Johannes Schaub-litb 指出的那样,数组类型可以用 初始化(zero-pack-expansion)
)。但是,17.6.3.1:2 还要求格式正确DefaultConstructible
,T()
数组类型并非如此,T
但std::is_default_constructible
.