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

Как функция перегрузки шаблона (сопоставление шаблонов) работает в std::vector вставить?

Рассмотрим следующие объявления std::vector (взятые из cplusplus - EASTL имеет те же декларации)

    iterator insert ( iterator position, const T& x );
    void insert ( iterator position, size_type n, const T& x );
template <class InputIterator>
    void insert ( iterator position, InputIterator first, InputIterator last );

Если я набираю

someVector.insert(someVector.begin(), 10, 90);

как это не запутано (компилятором) с последней перегрузкой, где 10 и 90 являются int и InputIterator, тип берется как int вместо альтернативы, которая должна принимать 10 как size_type и 20 как const int&?

Теперь я говорю "нет", потому что я реализую векторный контейнер (цели обучения), и в моем случае с вышеупомянутым вызовом третья перегрузка выбирается компилятором, а не второй перегрузкой и, следовательно, не компилируется. Если я удалю третью перегрузку, тогда все будет хорошо.

Это связано с тем, что вызывает последняя перегрузка (перегруженные функции с помощью свойств итератора)? Если это так, то если я должен был предположить, что все итераторы являются исходными указателями (хотя в моем случае я использую одно и то же объявление, это означает, что у меня есть перегрузка # 3 с шаблоном, ожидающим итератор... хотя ожидается неправильное здесь, потому что в конце концов это может быть что угодно, и в этом случае он интерпретируется как int для меня и не компилируется), как я буду уверен, что компилятор выбирает правильную функцию?

4b9b3361

Ответ 1

Из любопытства я взглянул на источники GCC:

  template<typename _InputIterator>
    void
    insert(iterator __position, _InputIterator __first,
           _InputIterator __last)
    {
      // Check whether it an integral type.  If so, it not an iterator.
      typedef typename std::__is_integer<_InputIterator>::__type _Integral;
      _M_insert_dispatch(__position, __first, __last, _Integral());
    }

Далее...

  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 438. Ambiguity in the "do the right thing" clause
  template<typename _Integer>
    void
    _M_insert_dispatch(iterator __pos, _Integer __n, _Integer __val,
                       __true_type)
    { _M_fill_insert(__pos, __n, __val); }

  // Called by the range insert to implement [23.1.1]/9
  template<typename _InputIterator>
    void
    _M_insert_dispatch(iterator __pos, _InputIterator __first,
                       _InputIterator __last, __false_type)
    {
      typedef typename std::iterator_traits<_InputIterator>::
        iterator_category _IterCategory;
      _M_range_insert(__pos, __first, __last, _IterCategory());
    }

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

Ответ 2

В реализации, вероятно, применяется SFINAE, которая в некоторых случаях является стандартным, чтобы гарантировать, что InputIterator фактически является итератором. Кроме того, компилятор будет только создавать экземпляр версии шаблона, если он не может сделать вызов для любых не-шаблонов.

Ответ 3

23.1.1/9 диктует, что он должен выбрать конструктор "целостный тип/значение" вместо конструктора "итератор/итератор", и компилятор должен убедиться, что он способен выполнить это определение.

[Стандартный текст]:

функции-члены в формах:

template <class InputIterator> // such as insert()
rt fx1(iterator p, InputIterator f, InputIterator l);

template <class InputIterator> // such as append(), assign()
rt fx2(InputIterator f, InputIterator l);

template <class InputIterator> // such as replace()
rt fx3(iterator i1, iteraror i2, InputIterator f, InputIterator l);

должен иметь тот же эффект, что и:

fx1(p, static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l));

fx2(static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l));

fx3(i1, i2, static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l));

если InputIterator является интегральным типом.

Ответ 4

В вашем случае вставка соответствует шаблону лучше, чем не-шаблон, если ваши параметры int и int.

Стандарт требует, чтобы он работал, как если бы не шаблон был выбран в любом случае!

- член действует в формах:

template <class InputIterator> // such as insert()
rt fx1(iterator p, InputIterator f, InputIterator l);

template <class InputIterator> // such as append(), assign()
rt fx2(InputIterator f, InputIterator l);

template <class InputIterator> // such as replace()
rt fx3(iterator i1, iteraror i2, InputIterator f, InputIterator l);

должен иметь тот же эффект, что и:

fx1(p,
    static_cast<typename X::size_type>(f),
    static_cast<typename X::value_type>(l));
fx2(static_cast<typename X::size_type>(f),
    static_cast<typename X::value_type>(l));
fx3(i1, i2,
    static_cast<typename X::size_type>(f),
    static_cast<typename X::value_type>(l));

если InputIterator является интегральным типом.

Итак, для решения этой проблемы должна быть какая-то метамагия.

Если вы измените свой вызов на someVector.insert(someVector.begin(), 10u, 90);, то не-шаблон будет может быть лучшим совпадением, в зависимости от того, что size_type.

Ответ 5

Kerrek находится на правильном пути. Авторы cplusplus.com, похоже, смотрят на что-то другое, кроме gcc. Если бы они взяли gander в gcc, они увидели бы, что на них наперчены комментарии, такие как // 438. Ambiguity in the "do the right thing" clause.

С++ 1998/2003, как и любой стандарт, имеет свою долю ошибок. Посмотрите на это так: Вы когда-нибудь писали идеальный код любого размера, идеальный документ? Стандарты не защищены. Они написаны людьми. По крайней мере, есть вероятность автоматического обнаружения ошибок в коде, который вы пишете: вы можете скомпилировать его, запустить против него некоторые инструменты. Как вы собираетесь проверять стандартный документ?

Стандарты разрабатываются комитетом. Некоторые из обновлений старого стандарта были объединением конкурирующих нестандартных схем от разных поставщиков. Другими обновлениями были новые концепции, которые, хотя они распространялись по всему комитету по стандартам, были проверены с помощью проверки на месте. Удивительно, что в текущем стандарте так мало ошибок, как и в предыдущем.