I am specializing the \'less\' (predicate) for a data type.
The code looks like this:
template<>
struct std::less
{
bool
If you need to specialize a standard algorithm, you can do so in the std namespace. It is the only thing that you are allowed to do inside that namespace according to the standard.
[lib.reserved.names]/1
It is undefined for a C++ program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified. A program may add template specializations for any standard library template to namespace std. Such a specialization (complete or partial) of a standard library template results in undefined behavior unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template
Now, the question is whether you actually want to specialize std::less
. Note that std::less
will call the comparison operator defined for your type, so you can provide that operation instead of specializing the template.
The problem with specializing std::less
for your particular type is that it will cause confusion if you provide a different operation than the one performed by operator<
for your type. If they perform the same operation, just leave the default std::less
definition without specialization.
If you do not want to provide the comparison operator, but still want to use the type in associative containers or with algorithms that require a comparator, you can provide an external comparison functor by other name that will not confuse other readers (and yourself somewhere in the future).
Even though the question has been answered by others with answers on how to specialize std::less
(by wrap them in a namespace block) and the right way to do it ( to overload operator <
).
However, C++
now allows (in C++11
) to speciliaze the way you did in your first example.
An explicit specialization shall be declared in a namespace enclosing the specialized template. An explicit specialization whose declarator-id is not qualified shall be declared in the nearest enclosing namespace of the template, or, if the namespace is inline (7.3.1), any namespace from its enclosing namespace set. Such a declaration may also be a definition. If the declaration is not a definition, the specialization may be defined later (7.3.1.2).
I tried the following code with g++ (8.3.0)
on my Ubuntu
machine.
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
class myType {
public:
myType(int in): i_(in) { }
int i_;
};
template <>
struct std::less<myType> {
bool operator()(const myType& a, const myType& b) const
{
return a.i_ < b.i_;
}
};
int main(int argc, char *argv[])
{
std::map<myType, std::string> vector = { { 1, "1"}, { 2, "2"}, { 3, "3"}, { 0, "0" } };
for (auto& i: vector)
std::cout << i.first.i_ << std::endl;
return 0;
}
The above code was compiled with
g++ --std=c++11 compare.cpp -Wall
The less functor doesn't have to be in std
namespace. So
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;
Works as expected. (Calls the functor you just created).
I guess you already know, but you can just write your own operator<(k1,k2), which is what default less functor looks for.
bool operator<(const DateTimeKey & k1, const DateTimeKey & k2)
{
//your code...
}
This is still the way to do it. Unfortunately you cannot declare or define functions within a namespace like you would do with a class: you need to actually wrap them in a namespace block.
Why are you even doing this?
std::less
exists for two purposes only:
There's no reason for a user to overload it - either overload operator<
or use a custom comparator function.
There are std algorithms that can be sensibly specialized - std::swap
is a good example - and to do so you do need to declare the specialization inside namespace std.