Требование (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
}
Еще одна ошибка в самом стандарте; 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
.
person
ecatmur
schedule
30.08.2012
struct block { int arr[4]; };
- person PiotrNycz   schedule 30.08.2012std::array<int, 4>
? - person ildjarn   schedule 30.08.2012