Почему перечисления не могут использоваться в качестве аргументов в этом векторном конструкторе?
Этот фрагмент кода:
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, который не квалифицируется как входной итератор, а затем конструктор не участвует в разрешении перегрузки.