Derive the 'this' pointer type when called from a derived class?

I have a method in a base class that needs a type passed to it for some type-related operations (lookup, size and some method invocation). Currently it looks like this:

class base
{
    template<typename T>
    void BindType( T * t ); // do something with the type
};

class derived : public base
{
    void foo() { do_some_work BindType( this ); } 
};

class derivedOther : public base 
{
    void bar() { do_different_work... BindType( this ); } 
};

However, I am wondering if there is a way to get the type of the caller without passing it so that the code of my code point becomes:

class derived : public base
{
  void foo() { BindType(); } 
};

Without an explicit pointer. I know that I can provide the template options explicitly as BindType<derived>(), but is there any way to somehow extract the caller type in some other way?

+4
source share
4 answers

It will not work as you expect

foo() :

class derived : public base           // <= YOU ARE IN CLASS DERIVED
{
public:
    void foo() { BindType( this ); }  // <= SO this IS OF TYPE POINTER TO DERIVED
};

, derived*. foo() derived_once_more, derived, derived*.

-

*

decltype(this) . :

class base
{
public: 
    template<typename T>
    void BindType( ) 
    { 
         cout << typeid(T*).name()<<endl;  // just to show the type 
    }
    virtual ~base() {};                    // for typeid() to work 
};
class derived : public base
{
public: 
    void foo() { BindType<decltype(this)>( ); } 
};

-

:

, , :

  • ( )
  • decltype (see above)
  • , ,
  • CRTP ( ).
+2

, CRTP ( ), :

class base
{
    template<typename T>
    void BindType(); // do something with the type
};

template <class T>
class crtper : base
{
     void BindDerived { BindType<T>(); }
}

class derived : public crtper<derived>
{
    void foo() { do_some_work BindDerived(); } 
};

class derivedOther : public crtper<derivedOther>
{
    void bar() { do_different_work... BindDerived(); } 
};

: , , foo , base. , . , , , . .

Edit2: , , - .

+4

BindType<derived>(), ( verbose, ) BindType<std::remove_reference<decltype(*this)>::type>();, . .

class base
{
protected:
    template<typename T>
    void BindType() { cout << typeid(T).name() << endl; } // do something with the type
};

class derived : public base
{
public:
    void foo()
    {
        BindType<std::remove_reference<decltype(*this)>::type>();
    }
};
+3

, CRTP, :

class base {
    using func_t = void(*)(void *);

    template<typename T>
    static void proto(void *ptr) {
        T *t = static_cast<T*>(ptr);
        (void)t;
        // do whatever you want...
    }

protected:
    inline void bindType() {
        func(this);
    }

public:
    template<typename T>
    base(T *): func{&proto<T>} {}

private:
    func_t func;
};

struct derived1: base {
    derived1(): base{this} {}

    void foo() {
         // ...
        bindType();
    }
};

struct derived2: base {
    derived2(): base{this} {}

    void bar() {
        // ...
        bindType();
    }
};

int main() {
    derived1 d1;
    d1.foo();

    derived2 d2;
    d2.bar();
}

, , this .
, .
. , proto , this .

, , .
, .


You can add static_assertto add Tan example restriction :

template<typename T>
base(T *t): func{&proto<T>} {
    static_assert(std::is_base_of<base, T>::value, "!");
}

This requires the inclusion of a header <type_traits>.

+2
source

Source: https://habr.com/ru/post/1658489/


All Articles