Как работает перегруженная функция выбора шаблона (сопоставление с образцом) в std :: vector insert? - PullRequest
17 голосов
/ 11 июля 2011

Рассмотрим следующие объявления 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 для меня и не компилируется) как я могу убедиться, что компилятор выбирает правильную функцию?

Ответы [ 5 ]

12 голосов
/ 11 июля 2011

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

  template<typename _InputIterator>
    void
    insert(iterator __position, _InputIterator __first,
           _InputIterator __last)
    {
      // Check whether it's an integral type.  If so, it's 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());
    }

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

1 голос
/ 11 июля 2011

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

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

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

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

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

template <class InputIterator> // such as replace()<br> 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.

1 голос
/ 11 июля 2011

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является целочисленным типом.

1 голос
/ 11 июля 2011

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

0 голосов
/ 11 июля 2011

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

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

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

...