Изискването (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