Is it valid to dereference this pointer in C++?

Viewed 216
struct myclass{
    static const int invalid = -1;
    /*explicit*/ myclass(int i, double d = 0.0){
        _var = i
    }
    int _var; 
    bool operator < (const myclass& rhs);
    bool operator > (const myclass& rhs);
    bool operator == (const myclass& rhs);
    bool operator != (const myclass& rhs);
    /*
    bool operator == (int rhs){
        return *(this) == myclass(rhs); // Is this valid C++ ?
    }
    bool operator != (int rhs){
        return *(this) == myclass(rhs); // Is this valid C++ ?
    }
    */
};

int userCodeCall() {
    myclass m(10);
    
    // Valid use Case
    if(m != myclass::invalid) {
        //.... do something
    }
    
    // Invalid use case
    if(m < 0.5) { // I want this to give me a compiler error
        //.... do something
    }
    // Invalid use case
    if(m < 5) { // I want this to give me a compiler error
        //.... do something
    }
}

I am working on a legacy codebase and I came across a class that can be implicitly constructed from int. And I found a bug where we were performing a < than comparison with a double. I thought of fixing this using an explicit with the constructor and then separately defining a == operation with an integer. But, I am not comfortable with the design. As I haven't seen this pattern anywhere else.

bool operator == (int rhs){
    return *(this) == myclass(rhs); // Is this valid C++ ?
}

I have two questions?

  1. Is it valid C++11/14/17?

  2. Can the design of the class be improved upon? Given I still want to have a "==" comparison style usage to stay valid as it is all over the user codebase.

    if(m != myclass::invalid) // some similar API need to be supported, if not the same.
    
2 Answers

The solution you have is fine, but it seems you just want to prevent specific comparison operators from working when numeric types are on the right hand side. You can do that by simply deleting those specific operators, for all types other than myclass.

template<typename T>
bool operator<(T) = delete;
    
template<typename T>
bool operator>(T) = delete;

The more common idiom for this kind of validity testing is to use an explicit operator bool:

struct myclass {
 private:
    static const int _invalid = -1;
    int _var;
 public:
    explicit myclass(int i, double d = 0.0){
        _var = i
    } 
    explicit operator bool() const { return _var != _invalid; }
    bool operator < (const myclass& rhs);
    bool operator == (const myclass& rhs);
    bool operator != (const myclass& rhs);
    bool operator > (const myclass& rhs);
};

int userCodeCall() {
    myclass m(10);
    
    // Valid use Case
    if(m) {
        //.... do something
    }
    
    // Invalid use case
    if(m < 0.5) { // gives a compile error
        //.... do something
    }
    // Invalid use case
    if(m < 5) { // gives a compile error
        //.... do something
    }
}

If this is too much and you must have a myclass::invalid to test against, you can just make it an instance of the class:

static constexpr myclass invalid(-1);
Related