应该(在C++ 11中)std :: vector :: resize(size_type)是否适用于默认的可构造的value_type int [4]?

Wal*_*ter 11 c++ default-constructor stdvector c++11

在C++ 11中,有两个版本std::vector::resize():

void resize( size_type count );
void resize( size_type count, const value_type& value);
Run Code Online (Sandbox Code Playgroud)

我理解(正如对该问题的答案之一的评论之一所建议的),第一个要求value_type是默认可构造的,而第二个要求它是可复制构造的.但是,(gcc 4.7.0)

using namespace std;
typedef int block[4];
vector<block> A;
static_assert(is_default_constructible<block>::value,";-("); //  does not fire
A.resize(100);                                               //  compiler error
Run Code Online (Sandbox Code Playgroud)

所以要么我的理解是错误的,要么gcc是错误的.哪一个?

eca*_*mur 10

关于vector.resize(n)格式良好的要求(23.3.6.3:10)T应该是CopyInsertable,即以下应该是格式良好的(23.2.1:13):

allocator_traits<A>::construct(m, p, v);
Run Code Online (Sandbox Code Playgroud)

其中A是向量的分配器类型,m是分配器,p属于类型T *v属于类型T.

正如您在20.6.8.2:5中发现的那样,这对于一般情况下的数组类型是无效的,因为它等同于调用

::new(static_cast<void *>(p))block(v);
Run Code Online (Sandbox Code Playgroud)

这对于数组类型无效(数组不能通过括号初始化).


实际上,你是正确的,g ++有一个bug; 它总是可以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
}
Run Code Online (Sandbox Code Playgroud)

另一个错误在于标准本身; 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.