Is it OK to inherit from the C++11 smart pointers and override the relative operators?

前端 未结 3 2069
野性不改
野性不改 2021-02-18 21:27

According to cppreference.com, std::shared_ptr provides a full set of relative operators (==, !=, <, ...), but the semantics of comparison aren\'t specified. I a

3条回答
  •  闹比i
    闹比i (楼主)
    2021-02-18 22:07

    The first thing, as others have already pointed out is that inheritance is not the way to go. But rather than the convoluted wrapper suggested by the accepted answer, I would do something much simpler: Implement your own comparator for your own types:

    namespace myns {
    struct mytype {
       int value;
    };
    bool operator<( mytype const& lhs, mytype const& rhs ) {
       return lhs.value < rhs.value;
    }
    bool operator<( std::shared_ptr const & lhs, std::shared_ptr const & rhs )
    {
       // Handle the possibility that the pointers might be NULL!!!
       // ... then ...
       return *lhs < *rhs;
    }
    }
    

    The magic, which is not really magic at all is Argument Dependent Lookup (aka. Koening Lookup or ADL). When the compiler encounters a function call it will add the namespace of the arguments to lookup. If the objects are the instantiation of a template, then the compiler will also add the namespaces of the types used to instantiate the template. So in:

    int main() {
       std::shared_ptr a, b;
       if ( a < b ) {                       // [1]
          std::cout << "less\n";
       } else {
          std::cout << "more\n";
       }
    }
    

    In [1], and because a and b are objects user defined types (*) ADL will kick in and it will add both std and myns to the lookup set. It will then find the standard definition of operator< for std::shared_ptr that is:

    template
    bool std::operator<(shared_ptr const& a, shared_ptr const& b) noexcept;
    

    And it will also add myns and add:

    bool myns::operator<( mytype const& lhs, mytype const& rhs );
    

    Then, after lookup finishes, overload resolution kicks in, and it will determine that myns::operator< is a better match than std::operator< for the call, as it is a perfect match and in that case non-templates take preference. It will then call your own operator< instead of the standard one.

    This becomes a bit more convoluted if your type is actually a template, if it is, drop a comment and I will extend the answer.


    (*) This is a slight simplification. Because operator< can be implemented both as a member function or a free function, the compiler will check inside std::shared_ptr<> for member operator< (not present in the standard) and friends. It will also look inside mytype for friend functions... and so on. But at the end it will find the right one.

提交回复
热议问题