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

Специализация "template <class _Tp> struct std:: less" в разных пространствах имен

Я специализирую "меньше" (предикат) для типа данных.

Код выглядит следующим образом:

template<>
struct std::less<DateTimeKey>
{
   bool operator()(const DateTimeKey& k1, const DateTimeKey& k2) const
   {
      // Some code ...
   }
}

При компиляции (g++ 4.4.1 на Ubuntu 9.10) я получаю сообщение об ошибке:

Специализация "struct struct std:: less" в разных пространствах имен

Я провел некоторое исследование и обнаружил, что существует "обходное решение", связанное с завершением специализации в пространстве имен std, то есть с изменением кода на:

namespace std {
template<>
struct less<DateTimeKey>
{
   bool operator()(const DateTimeKey& k1, const DateTimeKey& k2) const
   {
      // Some code ...
   }
}
}

который действительно закрывает компилятор. Однако это решение было от должности 5 лет ( "Великим" Виктором Базарофом не менее [неумышленно]. Является ли это исправление до сих пор, или есть лучший способ разрешить это, или же "старый способ" по-прежнему действителен?

4b9b3361

Ответ 1

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

Ответ 2

Если вам нужно специализировать стандартный алгоритм, вы можете сделать это в пространстве имен std. Это единственное, что вам разрешено делать внутри этого пространства имен в соответствии со стандартом.

[lib.reserved.names]/1

Это undefined для программы на С++. добавлять декларации или определения к пространства имен или пространства имен внутри пространство имен std, если иное указано. Программа может добавить шаблон специализации для любого стандарта шаблон библиотеки в пространство имен std. Такая специализация (полная или частичная) стандартной библиотеки результат шаблона в undefinedесли декларация не зависит от определяемое пользователем имя внешней связи и если специализация не встречается требования к стандартной библиотеке для исходный шаблон

Теперь возникает вопрос, хотите ли вы на самом деле специализироваться на std::less. Обратите внимание, что std::less вызовет оператор сравнения, определенный для вашего типа, поэтому вы можете предоставить эту операцию вместо специализации шаблона.

Проблема со специализацией std::less для вашего конкретного типа заключается в том, что это приведет к путанице, если вы предоставляете другую операцию, чем та, которая выполняется operator< для вашего типа. Если они выполняют одну и ту же операцию, просто оставьте определение по умолчанию std::less без специализации.

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

Ответ 3

Менее функтор не должен находиться в пространстве имен std. Так

struct A
{
    A(int _v=0):v(_v){}
    int v;
};


template<>  struct less<A>
{
    bool operator()(const A& k1, const A& k2) const
    {
        return k1.v < k2.v;
    }
};


std::map<A,int> m;
m[A(1)] = 1;
m[A(2)] = 2;

Работает так, как ожидалось. (Вызывается только что созданный функтор).

Я думаю, вы уже знаете, но вы можете просто написать свой собственный оператор < (k1, k2), который является тем, что ищет меньше функтора.

bool operator<(const DateTimeKey & k1, const DateTimeKey & k2)
{
//your code...
}

Ответ 4

Почему вы это делаете?

std::less существует только для двух целей:

  • чтобы дать имя оператору <, позволяющее ему передаваться как функтор
  • чтобы явно разрешить сравнение двух указателей, которые не находятся в одном массиве (что является технически незаконным, если сделано с необработанными указателями)

Нет причин для перегрузки пользователя - перегрузка operator< или использование пользовательской функции компаратора.

Существуют алгоритмы std, которые могут быть разумно специализированными - хороший пример - std::swap - и для этого вам нужно объявить специализацию в пространстве имен std.