Подтвердить что ты не робот

Должен (в С++ 11) std::vector:: resize (size_type) работать для конструктивного значения value_type по умолчанию по умолчанию [4]?

В С++ 11 есть две версии std::vector::resize():

void resize( size_type count );
void resize( size_type count, const value_type& value);

Я понимаю (как было предложено одним из комментариев к одному из ответов на этот вопрос), что для первого требуется, чтобы 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

Так что либо мое понимание было неправильным, либо gcc ошибкой. Что?

4b9b3361

Ответ 1

Требование (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:53, это недопустимо для типов массивов в общем случае, поскольку это эквивалентно вызову

::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.

Ответ 2

Я нашел это обсуждение после того, как столкнулся с аналогичной проблемой, при которой параметр resize() не работает для стандартного типа. Похоже, что реализация gcc-vector неверна.

FYI, я подал ошибку в gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64147