将基类模板的`this`类型化为其派生类

时间:2013-03-04 23:54:05

标签: c++ casting

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

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中包含一些允许自动对其模板类进行类型转换的事情似乎是合理的({{1 }})。

我追求的是T吗?有人可以提供代码示例来完成这项工作吗? This Question建议我可以这样做:

演员表总是在operator=this之间。

T*

但错误仍然存​​在。

2 个答案:

答案 0 :(得分:3)

  

虽然在我看来有些愚蠢,但如果我删除这一行[...]

,它就不会抱怨

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

  

问题可以通过明确的类型转换来解决,如[...]

我更喜欢static_cast<>

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

this函数收到的SaySomething()指针的类型为Base<Derived>,但您知道(按设计)指向的对象实际上是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); }

};

答案 1 :(得分: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()这样的显式函数更清晰,更安全。