简体   繁体   中英

c++ crosswise covariant: return type differs due to incomplete type

I am experimenting with covariance and came up with the following example that does at least not compile with clang 11 and on VS2015:

class Number {
public:
    virtual ~Number () = default;
    virtual Number const * increment()const = 0;
};

class Even;

class Odd : public Number {
public:
    // error: increment() is not covariant because Even is incomplete
    Even const * increment()const; 
};

class Even : public Number {
public:
    Odd const * increment()const;
};

It is related to Covariant return types, const-ness, and incomplete classes but not a duplicate because the constness is the same in both overwritten functions.

Is that even supported by the standard?

Is there a way to get around this problem or any suggestions to achieve a similar behavior?

While there may be workaround for what you're trying to achieve, the shown code is invalid.

According to class.virtual#9 :

If the class type in the covariant return type of D​::​f differs from that of B​::​f, the class type in the return type of D​::​f shall be complete at the point of declaration of D​::​f or shall be the class type D. ...

There's an example for this rule in the linked text.

In your case, since the return type of Odd::increment is not Number , and Even is incomplete at the point of declaring Odd::increment , the code is ill-formed.

I found the answer in this incorrect, and hence deleted answer written by @Brian in response to the question you've linked to.

You can achieve a similar thing with a non-virtual interface (though it has more lines and seems easier to mess up):

class Number {
public:
    virtual ~Number() = default;
    Number const * increment() const { return do_increment(); }
private:
    virtual Number const * do_increment() const = 0;
};

class Even;

class Odd : public Number {
public:
    Even const * increment() const;
private:
    Number const * do_increment() const override;
};

class Even : public Number {
public:
    Odd const * increment() const { return do_increment(); }
private:
    Odd const * do_increment() const override;
};

inline Even const * Odd::increment() const {
    return static_cast<Even const *>(do_increment());
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM