Почему перечисления не могут использоваться в качестве аргументов в этом векторном конструкторе?

Этот фрагмент кода:

enum {N = 10, M = 100};

vector<int> v(N, M);

не удается скомпилировать с Visual Studio 2013 из-за следующей ошибки:

ошибка C2838: 'iterator_category': незаконное квалифицированное имя в объявлении участника

Что с ним не так?

Ответы

Ответ 1

Это ошибка как для VS2012, так и для VS2013, поскольку она не соответствует стандарту С++ 11 (с _HAS_CPP0X, определяемым как 1):

С++ 03 23.1.1 [lib.sequence.reqmts]/9 говорит:

Для каждой последовательности, определенной в этом разделе и в пункте 21:

- конструктор template <class InputIterator> X(InputIterator f, InputIterator l, const Allocator& a = Allocator()) должен иметь тот же эффект, что и:

X(static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l), a), если InputIterator является интегральным типом.

но из С++ 11 23.2.3 [sequence.reqmts]/14:

Для каждого контейнера последовательности, определенного в этом разделе и в пункте 21:

- Если конструктор template <class InputIterator> X(InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()) вызывается с типом InputIterator, который не квалифицируется как входной итератор, , тогда конструктор не должен участвовать в разрешении перегрузки.

Этот конструктор не должен рассматриваться вообще

Подробнее здесь: fooobar.com/questions/382109/...

В качестве обходного решения вы можете "немного помочь в разрешении перегрузки", например

std::vector<int> v(static_cast<std::vector<int>::size_type>(N), M);

Ответ 2

Так как С++ 11 конструктор vector, принимающий два InputIterators, должен быть отключен, если два аргумента не являются итераторами. VS2013 не реализует это правильно.

Ответ 3

Это ошибка Visual Studio 2013, сгенерированная ошибка (видеть ее в прямом эфире), это всего лишь небольшая часть:

[...]

см. ссылку на экземпляр шаблона функции 'std::vector > :: vector <, void > (_ Iter, _Iter)' скомпилировано

[...] >

Он пытается использовать конструктор, который принимает два итератора ввода. Что будет ошибкой, оба gcc и clang отлично справляются с этим кодом.

Мы можем, что в С++ 11 этот конструктор не следует учитывать:

Создает контейнер с содержимым диапазона [первым, последним]. Этот конструктор не участвует в разрешении перегрузки, если InputIt не удовлетворяет InputIterator, чтобы избежать двусмысленности с перегрузкой 2 (поскольку С++ 11)

Это согласуется с стандартным разделом проекта С++ 11 23.2.3, который гласит:

Если конструктор

template <class InputIterator>
X(InputIterator first, InputIterator last,
  const allocator_type& alloc = allocator_type())

вызывается с типом InputIterator, который не квалифицируется как входной итератор, а затем конструктор не участвует в разрешении перегрузки.