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

Почему стандартные контейнеры используют шаблоны функций вместо не-шаблонных операторов Koenig

Этот вопрос вдохновлен Проблема с std:: reference_wrapper. Скажем, например, operator< для std::vector. Он определяется как шаблон функции как

template< class T, class Alloc >
bool operator<( const vector<T,Alloc>& lhs,
                const vector<T,Alloc>& rhs );

В результате неявное преобразование аргумента функции в тип соответствующего параметра функции отрицается (в основном из-за его характера шаблона). Это значительно снижает полезность и удобство std::reference_wrapper. Например, вы не можете использовать std::sort на std::vector<std::reference_wrapper<std::vector<int>>>.

С другой стороны, все проблемы решаются, только если operator< определяется как не-шаблонный оператор Koenig, например

template <...>
class vector ... {
  friend bool operator<(const vector& a, const vector& b) {...}
};

Мне интересно, почему стандартная библиотека приняла вместо этого прежний подход?

4b9b3361

Ответ 1

Рассмотрим этот код (A.h):

template <class T>
class A {
  public:
  T m_x;

  friend bool operator<(const A & lhs, const A & rhs) {
    return lhs.m_x < rhs.m_x;
  }
};

И main.cpp:

#include "A.h"

namespace buddy {
bool operator<(const A<double> & lhs, const A<double> &rhs) {
    return lhs.m_x > rhs.m_x;
};
}
using namespace buddy;
int main(int argc, char ** argv) {

  A<double> a1;
  A<double> a2;

  a1 < a2;

  return 0;
}

Этот код не компилируется:

main.cpp: 14: 5: ошибка: неоднозначная перегрузка для 'operator < (типы операндов - "A" и "A" ) a1 < а2;

Причина, конечно, в том, что оба оператора < являются точными совпадениями. С другой стороны, если мы изменим первый оператор < to (определяется вне класса):

template <class T>
bool operator<(const A<T> & lhs, const A<T> & rhs) {
  return lhs.m_x < rhs.m_x;
}

Компилятор перестает жаловаться: теперь это конкуренция между точным соответствием и шаблоном функции, поэтому используется точное совпадение.

Если оператор < был определен таким образом, который вы предлагаете, не было бы разумного способа для пользователей std::vector переопределить поведение оператора <, не относящегося к специализации std::vector, что намного больше работает.

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