整形式であるための要件(23.3.6.3:10)vector.resize(n)
は、次のようにする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
}
もう1つのバグは、標準自体にあります。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
。