繁体   English   中英

协变量返回类型取决于模板类typedef

[英]covariant return type depending on a template class typedef

就像每次我尝试混合通用编程和多态性一样,我也不得不为我的编译器苦苦挣扎。 C ++很有趣,但是很困难(嗯,我的大脑也很复杂,这无济于事)。

我在下面的简化但相似的情况下写了相同的编译器错误:

template<typename Object>
class Environment;

class Boat {
};

template<typename Object>
class Worker {
public:
    typedef Object      Object_type;
public:
                        Worker() {}
    virtual             ~Worker() throw() {}
    virtual bool        work() = 0;
    virtual const Environment<Object>*
                        env() const=0;
};

template<typename Object>
class Environment {
public:
    typedef Object      Object_type;
public:
                        Environment() {}
    virtual             ~Environment() throw() {}
    virtual Worker<Object>*   
                        spawnWorker() const=0;
};

template<typename Employee>
class Enterprise;

template<typename Object>
class Painter: public Worker<Object> {
public:
    using typename      Worker<Object>::Object_type;
    typedef Enterprise<Painter<Object_type> >       
                        Environment_type;
public:
                        Painter( const Environment_type *env) : enterprise(env){}
    const Environment_type*
                        env() const override {return enterprise; }
    bool                work() override {return true;}
private:
    const Environment_type* const              
                        enterprise;
};

template<typename Employee>
class Enterprise: public Environment<typename Employee::Object_type> {
public:
    using typename      Environment<typename Employee::Object_type>::Object_type;
public:
                        Enterprise() {}
                        ~Enterprise() throw() {}
    Worker<Object_type>*  
                        spawnWorker() const override { return new Painter<Object_type>(this); }
};

int main() {
    Enterprise< Painter<Boat> > enterprise;
    auto painter=enterprise.spawnWorker();
    painter->work();

    delete painter;

    return 0;
}

g ++给出错误:

test.cpp: In instantiation of ‘class Painter<Boat>’:
test.cpp:50:7:   required from ‘class Enterprise<Painter<Boat> >’
test.cpp:61:33:   required from here
test.cpp:42:25: error: invalid covariant return type for ‘const Environment_type* Painter<Object>::env() const [with Object = Boat; Painter<Object>::Environment_type = Enterprise<Painter<Boat> >; typename Worker<Object>::Object_type = Boat]’
                     env() const override {return enterprise; }
                     ^
test.cpp:16:25: error:   overriding ‘const Environment<Object>* Worker<Object>::env() const [with Object = Boat]’
                     env() const=0;`

和clang ++可能更容易理解:

test.cpp:42:25: error: return type of virtual function 'env' is not covariant with the return type of the function it overrides ('const Environment_type *' (aka 'const Enterprise<Painter<Object_type> > *') is not derived from 'const Environment<Boat> *')
                        env() const override {return enterprise; }
                        ^
test.cpp:50:47: note: in instantiation of template class 'Painter<Boat>' requested here
class Enterprise: public Environment<typename Employee::Object_type> {
                                              ^
test.cpp:61:33: note: in instantiation of template class 'Enterprise<Painter<Boat> >' requested here
    Enterprise< Painter<Boat> > enterprise;
                                ^
test.cpp:16:25: note: overridden virtual function is here
                        env() const=0;
                        ^

我该如何解决这个问题? 如果解决方案仍然更好:

  • 使env()实现的返回类型保持协变
  • 获取编译器,该编译器从Enterprise的Employee模板参数推断环境的Object模板参数

如注释中所述,问题在于派生类试图使用其他返回类型重写函数。 您可以通过替换PainterEnvironment_type定义来解决此问题:

typedef Environment<Object> Environment_type;

我无法确切地说出此修复程序是否对您的想法有意义,但是我想,它将为您提供想法。

但是总体设计看起来有些奇怪。 这是我的中心问题:

您是否真的想让Worker成为继承树的根并将其用于运行时多态? 我问是因为您不能混合使用Worker<boat>Worker<house>指针。 它们是完全不同的东西,其虚拟功能不匹配。

如果您真的想使用运行时多态性,建议使用非模板基类。 例如,一家船舶涂漆企业将只产生一个指向普通工人而不是船舶油漆工的指针。 如果你需要它真正产生一个船的画家,那么我会说,继承(在这种情况下,为企业/环境)是不是你想要的。

如果确实需要基类(但不需要运行时多态性),则可能需要研究CRTP。 它看起来很奇怪,可能会引发更多问题,但是它是一个功能强大的工具,提供了另一层编译时多态性。

如果您需要某个接口,但不一定需要一个继承链,则可能还需要研究类型擦除。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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