开发者

Use of derived class' typedefs in base

开发者 https://www.devze.com 2023-01-31 19:21 出处:网络
I want the derived class to be a descendant of a template class. That class depends on descendant\'s members.

I want the derived class to be a descendant of a template class. That class depends on descendant's members. In short I want this code to compile:

struct IBootParams
{
    virtual bool GetImmediate() = 0;
};

template <class T>
struct TBootBootParams
{
    typename T::TransType transferType;

    typename T::UseAbort_ useAbort;

    bool GetImmediate()
    {
        if ( transferType == T::e1 )
        {
            return useAbort.someFlag;
        }

        return false;
    }

};

struct BootBootParams : public TBootBootParams<BootBootParams> 
{
    enum SomeEnum
    {
        e1=0,
        e2,
        e3
    };

    struct UseAbort
    {
        bool        someFlag;           

        char        someMember;             
        int         otherMember;        
    } useAbort;

    typedef SomeEnum TransType;
    typedef Use开发者_运维问答Abort UseAbort_;
};

struct BootAltBootParams : public TBootBootParams<BootAltBootParams> 
{
    enum SomeEnum
    {
        e1=5,
        e2,
        e3
    };

    struct UseAbort
    {
        bool        someFlag;           

        long long       someMember;             
        long long       otherMember;        
    } useAbort;

    typedef SomeEnum TransType;
    typedef UseAbort UseAbort_;
};

int _tmain(int argc, _TCHAR* argv[])
{
    BootBootParams bp;
    BootAltBootParams bpa;

    bool f = bp.GetImmediate();
    f = bpa.GetImmediate();
}


You can't do it this way. When the compiler instantiates TBootBootParams<BootBootParams> it has not yet completely read the whole definition of BootBootParams so you can't access its members from inside the definition of TBootBootParams (member functions of TBootBootParams are an exception because they are instantiated later).

The usual solution is to have a traits class:

template<class T> struct TBootBootParams_traits;

template <class T>
struct TBootBootParams
{
    typename TBootBootParams_traits<T>::TransType transferType;

    typename TBootBootParams_traits<T>::UseAbort_ useAbort;

    bool GetImmediate()
    {
        if ( transferType == TBootBootParams_traits<T>::e1 )
        {
            return useAbort.someFlag;
        }

        return false;
    }

};

struct BootBootParams;
template<> struct TBootBootParams_traits<BootBootParams>
{
    enum SomeEnum
    {
        e1=5,
        e2,
        e3
    };

    struct UseAbort
    {
        bool        someFlag;           

        long long       someMember;             
        long long       otherMember;        
    };

    typedef SomeEnum TransType;
    typedef UseAbort UseAbort_;
};

struct BootBootParams : 
    public TBootBootParams<BootBootParams>, 
    public TBootBootParams_traits<BootBootParams>
{
    UseAbort_ useAbort;
};


There is no way this can work that isn't a bit of a hack. So here is my attempt at a bit of a hack:

struct IBootParams
{
    virtual bool GetImmediate() = 0;
};

template <class T>
struct TBootBootParams : public IBootParams
{
    typename T::TransType transferType;

    typename T::UseAbort_ useAbort;

    virtual bool GetImmediate()
    {
        if ( transferType == T::e1 )
        {
            return useAbort.someFlag;
        }

        return false;
    }

};

struct BootBootParams_types
{
    enum SomeEnum
    {
        e1=0,
        e2,
        e3
    };

    struct UseAbort
    {
        bool        someFlag;

        char        someMember;
        int         otherMember;
    } useAbort;

    typedef SomeEnum TransType;
    typedef UseAbort UseAbort_;
};

struct BootBootParams : public BootBootParams_types,
                        public TBootBootParams<BootBootParams_types>
{
};

struct BootAltBootParams_types
{
    enum SomeEnum
    {
        e1=5,
        e2,
        e3
    };

    struct UseAbort
    {
        bool        someFlag;

        long long       someMember;
        long long       otherMember;
    } useAbort;

    typedef SomeEnum TransType;
    typedef UseAbort UseAbort_;
};

struct BootAltBootParams : public BootAltBootParams_types,
                           public TBootBootParams<BootAltBootParams_types>
{
};

int main(int argc, const char * argv[])
{
    BootBootParams bp;
    BootAltBootParams bpa;

    bool f = bp.GetImmediate();
    f = bpa.GetImmediate();
}


Does this do what you want? It compiles.

struct IBootParams
{
    virtual bool GetImmediate() = 0;
};

template <class T>
struct TBootBootParams
{
    bool GetImmediate()
    {
        if ( static_cast<T*>(this)->transferType == T::e1 )
        {
            return static_cast<T*>(this)->useAbort.someFlag;
        }

        return false;
    }

};

struct BootBootParams : public TBootBootParams<BootBootParams> 
{
    enum SomeEnum
    {
        e1=0,
        e2,
        e3
    } transferType;

    struct UseAbort
    {
        bool        someFlag;           

        char        someMember;             
        int         otherMember;        
    } useAbort;
};

struct BootAltBootParams : public TBootBootParams<BootAltBootParams> 
{
    enum SomeEnum
    {
        e1=5,
        e2,
        e3
    } transferType;

    struct UseAbort
    {
        bool        someFlag;           

        long long       someMember;             
        long long       otherMember;        
    } useAbort;
};

int main(void)
{
    BootBootParams bp;
    BootAltBootParams bpa;

    bool f = bp.GetImmediate();
    f = bpa.GetImmediate();
}


I tried a little change to ybungalobill's solution counting my own needs. And this what I got

template<class T> 
struct TBootBootParams_traits;

template <class T>
struct TBootBootParams
{
    typedef TBootBootParams_traits<T> Traits;

    typename Traits::TransType transferType;
    typename Traits::UseAbort_ useAbort;

    bool GetImmediate()
    {
        if ( transferType == TBootBootParams_traits<T>::e1 )
        {
            return useAbort.someFlag;
        }

        return false;
    }
};

struct BootBootParams;
struct BootAltBootParams;

template<> 
struct TBootBootParams_traits<BootBootParams>
{
    enum SomeEnum
    {
        e1=5,
        e2,
        e3
    };

    struct UseAbort
    {
        bool        someFlag;           

        long long       someMember;             
        long long       otherMember;        
    };

    typedef SomeEnum TransType;
    typedef UseAbort UseAbort_;
};

template<> 
struct TBootBootParams_traits<BootAltBootParams>
{
    enum SomeEnum
    {
        e1=5,
        e2,
        e3
    };

    struct UseAbort
    {
        bool        someFlag;           

        int someMember;             
        float otherMember;        
    };

    typedef SomeEnum TransType;
    typedef UseAbort UseAbort_;
};

struct BootBootParams : 
    public TBootBootParams<BootBootParams>
{

};

struct BootAltBootParams : 
    public TBootBootParams<BootAltBootParams>
{

};

int main(void)
{
    BootBootParams bp;
    BootAltBootParams bpa;

    bool f = bp.GetImmediate();
    f = bpa.GetImmediate();
}

To summarize.. I use a template class as a must-have option of another class for this class placing all type data there. This just what I needed. Thanks again for the option!


For this approach to work, you have to include the template class object as a member of the parent class.

0

精彩评论

暂无评论...
验证码 换一张
取 消