微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

转发CRTP派生的类方法的返回类型

如何解决转发CRTP派生的类方法的返回类型

我想通过CRTP使用“静态多态性”来执行以下操作:

template <typename T>
struct Base
{
    double get_value() const { return ((T*)this)->_get_value(); }

protected:
    ~Base() {}
};

struct Derived1 : public Base<Derived1>
{
    double value;

    Derived1() : value(3.) {}

    const double& _get_value() const { return value; }
};

struct Derived2 : public Base<Derived2>
{
    double _get_value() const { return 5.; }
};

这可行,但是对于对象实例化为Derived1的情况,我也希望get_value返回对该值的const引用,而不返回副本。因此,从某种意义上说,这是一种对返回值的“完美转发”。

我试图声明get_value的返回类型,如下所示:

template <typename T>
struct Base
{
    decltype(std::declval<T>()._get_value()) get_value() const { return ((T*)this)->_get_value(); }
    ...

但毫不奇怪,海湾合作委员会抱怨说这是invalid use of incomplete type 'struct Derived1'

有什么办法解决这个问题吗?

提前谢谢! :)

解决方法

GCC拒绝OP中提出的解决方案的原因是Base<Derived1>之前 Derived1实例化。此实例化包括所有成员函数的签名的实例化,但不实例化函数体本身。

因此,我们需要推迟确定成员函数的签名/返回类型,直到之后 Derived1可见。

一种方法是通过decltype(auto)推迟确定返回类型。这使得返回类型取决于函数主体(不会立即实例化)。不幸的是,这是C ++ 14的功能。

template <typename T>
struct Base
{
    decltype(auto) get_value() const { return ((T*)this)->_get_value(); }

protected:
    ~Base() {}
};

请参见https://godbolt.org/z/r1T56n


dcl.spec.autotemp.inst可能涵盖了这一点。


或者,即使在C ++ 11中,也可以通过将函数转换为函数模板来推迟确定返回类型,如果需要,可以依赖于某些伪参数:

template <typename T>
struct Base
{
    template<typename U=T>
    decltype(std::declval<U>()._get_value()) get_value() const {
        return ((T*)this)->_get_value();
    }

protected:
    ~Base() {}
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。