Specialization of 'template struct std::less' in different namespace

后端 未结 5 1973
予麋鹿
予麋鹿 2020-12-03 13:42

I am specializing the \'less\' (predicate) for a data type.

The code looks like this:

template<>
struct std::less
{
   bool          


        
相关标签:
5条回答
  • 2020-12-03 13:43

    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).

    0 讨论(0)
  • 2020-12-03 13:49

    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 
    
    0 讨论(0)
  • 2020-12-03 13:51

    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...
    }
    
    0 讨论(0)
  • 2020-12-03 13:53

    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.

    0 讨论(0)
  • 2020-12-03 14:07

    Why are you even doing this?

    std::less exists for two purposes only:

    1. to give a name to operator <, allowing it to be passed as a functor
    2. to explicitly allow comparing two pointers that aren't in the same array (which is technically illegal if done with raw pointers)

    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.

    0 讨论(0)
提交回复
热议问题