g ++ 4.9 ошибка в разрешении std :: vector & lt; C_type_array & gt;

Рассмотрим следующий код:

#include <iostream>
#include <vector>
#include <array>

using namespace std;

typedef double (C_array)[10];

int main()
{
std::vector<C_array> arr(10);

// let's initialize it
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
arr[i][j] = -1;

// now make sure we did the right thing
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
cout << arr[i][j] << " ";
}
cout << endl;
}
}

Я только что узнал от @juanchopanza https://stackoverflow.com/a/25108679/3093378 что этот код не должен быть законным, так как старый C-стиль массива нельзя назначать / копировать / перемещать. тем не мение g++ пролетает через код, даже с -Wall -Wextra -pedantic, clang++ не компилирует это. Конечно, если я попытаюсь сделать что-то вроде auto arr1 = arr;, он терпит неудачу под g++так как не умеет копировать arr в arr1,

я использовал g++4.9 от macports под OS X Mavericks.
Живой код здесь: http://goo.gl/97koLa

Мои вопросы:

  1. Является ли этот код незаконным в соответствии со стандартом?
  2. Является g++ так глючит? Я продолжаю находить много простых примеров, в которых g++ слепо компилирует нелегальный код, последний был вчера определяемый пользователем приоритет операторов преобразования, компилируется в g ++, но не в clang ++ , и без особых усилий, просто экспериментируя с C++ ради забавы.

7

Решение

Ваш код недействителен C ++ 03. Во-первых, заголовок <array> не является частью стандартной библиотеки C ++ 03, но здесь она также не нужна. Во-вторых, конструкция векторного объекта пытается вызвать конструктор

explicit vector(size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type());

Однако инициализация val не удалась по той же причине, по которой вы не можете написать

C_array foo = C_array();

Насколько я понимаю, параграф 2 в разделе 5.2.3 стандарта C ++ 03 допускает это обозначение только для типов, не являющихся массивами:

Выражение T (), где T — спецификатор простого типа (7.1.5.2) для типа объекта, не являющегося полным массивом, или типа void (возможно, cv-квалифицированного), создает значение rvalue указанного типа, которое является значением -инициализированный (8.5; инициализация не производится для случая void ()).

Кроме того, g ++ — 4.9.0 также отказывается компилировать код, если в командной строке не указано -std = c ++ 11:

foo.cpp: In constructor ‘std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = double [10]; _Alloc = std::allocator<double [10]>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = double [10]; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<double [10]>]’:
foo.cpp:11:32: error: functional cast to array type ‘std::vector<double [10]>::value_type {aka double [10]}’
std::vector<C_array> arr(10);
...

Что касается C ++ 11, то векторный контейнер предлагает дополнительный конструктор заливки:

explicit vector (size_type n);

Этот конструктор требует, чтобы тип шаблона был конструируемым по умолчанию (см. Раздел 23.3.6.2). Насколько я понимаю, это требование также не выполняется в C ++ 11 (см. Раздел 17.6.3.1), поскольку для удовлетворения требования выражение C_array () должно создать временный объект, который также недопустим в C + +11 (снова см. Раздел 5.2.3). Я не знаю, требует ли стандарт, чтобы компилятор отклонял код, или компилятору разрешено его компилировать, если не выполняется одно из требований, но реализация стандартной библиотеки просто не нуждается в нем. Может быть, люди, которые знают больше о C ++ 11, могут заполнить пробелы здесь.

Помимо всего этого, на мой взгляд, не стоит пытаться использовать массив в качестве типа элемента контейнера, поскольку другие требования контейнера не выполняются. Например, C_array не может быть вставлен при копировании, и, следовательно, вектор не может быть скопирован.

По поводу вашего второго вопроса: не стесняйтесь просматривать базу данных gcc bugzilla по адресу https://gcc.gnu.org/bugzilla/. Однако принятие недействительного кода также может быть сделано специально, например, чтобы не нарушать унаследованный код.

2

Другие решения


По вопросам рекламы [email protected]