【问题标题】:Forwarding of return types of CRTP-derived class methods转发 CRTP 派生类方法的返回类型
【发布时间】:2020-10-15 09:23:40
【问题描述】:

我想通过 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(); }
    ...

但不出所料,GCC 抱怨这是invalid use of incomplete type 'struct Derived1'

有没有办法解决这个问题?

提前感谢您! :)

【问题讨论】:

  • gcc 和 clang 之间关于受保护的析构函数的行为有一个有趣的差异:godbolt.org/z/W6M8Mo 也许你想问另一个问题(我也会感兴趣) - 编辑:啊,那是仅在 C++20 中但不在 C++11 模式下 oO

标签: c++ c++11 crtp perfect-forwarding static-polymorphism


【解决方案1】:

GCC 拒绝 OP 中提议的解决方案的原因是 Base&lt;Derived1&gt; 正在被实例化之前 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() {}
};

【讨论】:

  • 我希望我的实例化顺序正确,我有点生疏了。
  • 完美,我使用了您的解决方案 #2,它完全按照需要工作。谢谢!! :)
  • @PabloGrube 我认为decltype(auto) 是更传统的完美转发返回类型的方式。 declval 构造的主要区别在于 declval 对 SFINAE 友好。
  • 不幸的是auto在C++14之前不存在返回类型,问题被标记为[c++11] :)
  • @Quentin 啊,谢谢,我想我已经用-std=c++11 测试过了...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-10
  • 1970-01-01
  • 2020-03-30
相关资源
最近更新 更多