Специализация 'template <class _Tp> struct std :: less' в другом пространстве имен - PullRequest
26 голосов
/ 17 февраля 2010

Я специализирую 'less' (предикат) для типа данных.

Код выглядит так:

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

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

Специализация 'template struct std :: less' в другом пространстве имен

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

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

, что действительно закрывает компилятор.Тем не менее, это решение было с поста 5 лет («Великим» Виктором Базарофом не меньше [каламбур непреднамеренно]).Это исправление все еще уместно, или есть лучший способ решить эту проблему, или «старый способ» все еще действителен?

Ответы [ 4 ]

25 голосов
/ 17 февраля 2010

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

24 голосов
/ 17 февраля 2010

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

[lib.reserved.names] / 1

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

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

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

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

3 голосов
/ 17 февраля 2010

Почему ты вообще это делаешь?

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

  1. для присвоения имени оператору <, что позволяет передавать его как функтор </li>
  2. чтобы явно разрешить сравнение двух указателей, которые не находятся в одном и том же массиве (что технически недопустимо, если делается с необработанными указателями)

У пользователя нет причин перегружать его - либо перегрузите operator<, либо используйте пользовательскую функцию сравнения.

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

3 голосов
/ 17 февраля 2010

Меньший функтор не обязательно должен находиться в пространстве имен 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), который по умолчанию ищет менее функтор. </p>

bool operator<(const DateTimeKey & k1, const DateTimeKey & k2)
{
//your code...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...