2

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

这可行,但我也希望在对象被实例化为的情况下Derived1get_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'.

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

先感谢您!:)

4

1 回答 1

2

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

所以我们需要推迟确定成员函数的签名/返回类型,直到after Derived1可见。

一种方法是通过推迟确定返回类型 via 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() {}
};
于 2020-10-15T09:43:49.490 回答