3

我的代码的简化版本如下所示:

template <class T>
struct Base
{
    void SayHello( T* aDerived )
    {
    }

    void SaySomething()
    {
        SayHello( this ); // This is where the error happens
    }
};

struct Derived : public Base< Derived >
{
};

int main(int argc, const char * argv[])
{
    Derived iDerived;
    iDerived.SaySomething();
}

并且它不会在SayHello( this )出现此错误消息的行上编译:

Cannot initialize a parameter of type 'Derived *'
with an rvalue of type 'Base<Derived> *'

现在编译器抱怨这一点是有道理的,尽管在我看来有点愚蠢,如果我删除这一行它不会抱怨:

iDerived.SaySomething();

无论如何,可以通过执行显式类型转换来解决问题,如下所示:

SayHello( (T*)this );

Base问题是我的实际代码以许多这些类型转换结束,在我看来,只包含允许它自动转换到其模板类(T)的东西似乎是合理的。

operator=我追求的吗?有人可以提供一个代码示例来说明这是如何完成的吗?这个问题表明我可以做类似的事情:

演员表总是介于this和之间T*

operator T*()
{
    return (T*)this;
}

但错误仍然存​​在。

4

2 回答 2

3

尽管在我看来有些愚蠢,但如果我删除此行并不会抱怨 [...]

不,这并不愚蠢,这就是模板的工作方式。如果你从不调用它,类模板的成员函数将永远不会被实例化。因此,在实例化它们时会产生的编译错误不会出现。

这个问题可以通过做一个明确的类型转换来解决,就像这样 [...]

我更喜欢一个static_cast<>

SayHello( static_cast<T*>(this) );

您的函数接收到的this指针SaySomething()是 type Base<Derived>,但您知道(通过设计)指向的对象实际上是 type Derived。因此,执行静态转换是安全的。

在我看来,只在 Base 中包含一些允许将其自动类型转换为其模板类 (T) 的东西似乎是合理的。

在这种情况下,多次转换指针并没有错。这就是 CRTP(您正在使用的设计模式)强制您执行的操作。如果您对此感到困扰,只需定义一个get_this()为您执行强制转换的函数:

template <class T>
struct Base
{
    void SayHello( T* aDerived )
    {
    }

    void SaySomething()
    {
        SayHello( get_this() );
    }

private:

    // Version returning a non-const pointer
    T* get_this() { return static_cast<T*>(this); }

    // Version returning a const pointer
    T const* get_this() const { return static_cast<T const*>(this); }

};
于 2013-03-04T23:56:18.790 回答
3

您可以添加一个辅助函数,将this向下转换返回到派生类型

template <class T>
struct Base
{
    void SayHello( T* aDerived )
    {
    }

    void SaySomething()
    {
        SayHello( derived_this() );
    }

private:
    T* derived_this()
    {
        return static_cast<T*>(this);
    }

您可能还需要const重载:

    const T* derived_this() const
    {
        return static_cast<const T*>(this);
    }

可以添加一个隐式转换运算符,但我不推荐它:

    operator T*() { return static_cast<T*>(this); }

隐式转换削弱了类型系统并且可能成为错误的来源,我认为像这样的显式函数derived_this()更清晰、更安全。

于 2013-03-05T00:06:18.017 回答