0

I am stuck with an object slicing problem when using CRTP. The following mock illustrates my problem.

#include <memory>

class CrtpGenr
{
};

template<class t_object>
class CrtpBase : public CrtpGenr
{
    public:
        static
        auto create() -> std::unique_ptr<t_object> {
            return(std::unique_ptr<t_object>(new t_object));
        }
        void funct1(){}
};

class CrtpDirv1 : public CrtpBase<CrtpDirv1>
{
    public:
        void funct2(){}
};

class CrtpDirv2 : public CrtpBase<CrtpDirv2>
{
    public:
        void funct2(){}
};


int main()
{
/*
    // This works
    std::unique_ptr<CrtpDirv1> crtp_obj = CrtpDirv1::create();
    crtp_obj->funct1();
    crtp_obj->funct2();
*/

    std::unique_ptr<CrtpGenr> crtp_obj1 = static_cast<std::unique_ptr<CrtpGenr>>(CrtpDirv1::create());
    std::unique_ptr<CrtpGenr> crtp_obj2 = static_cast<std::unique_ptr<CrtpGenr>>(CrtpDirv2::create());
    crtp_obj1->funct1();
    crtp_obj1->funct2();

    return 0;
}

Compiling the above code gives me the following error:

main.cpp: In function 'int main()':
main.cpp:47:16: error: 'class CrtpGenr' has no member named 'funct1'
 crtp_obj1->funct1();
            ^
main.cpp:48:16: error: 'class CrtpGenr' has no member named 'funct2'
 crtp_obj1->funct2();

I would like to be able to cast the CrtpDirv1 and CrtpDirv2 classes to CrtpGenr. This is so that I can define a container of type CrtpGenr to hold objects of either CrtpDirv1 or CrtpDirv2. What am I doing wrong?

vixiv
  • 161
  • 8
  • The `static_cast`s should not compile. Are you providing all the errors? – Cheers and hth. - Alf Mar 30 '16 at 06:17
  • @ Alf: Yes I have compiled the same exact code in coliru and the errors I have provided is what is given there. [link] (http://coliru.stacked-crooked.com/a/5a643b61336c250c) – vixiv Mar 30 '16 at 06:21
  • @alf - the static_casts compile just fine ( http://cpp.sh/8zg6 ). But I'm not sure why anybody would expect lines 47 and 48 to compile. – Arunas Mar 30 '16 at 06:26
  • Sorry about that comment about the `static_cast`s. I'd forgotten that `unique_ptr` has a templated converting constructor. Which makes it type-unsafe (in the general case it can easily send you to UB-land), which may be why I'd forgotten it. – Cheers and hth. - Alf Mar 30 '16 at 06:33

1 Answers1

0

*crtp_obj1 is of type CrtpGenr - as you claim in line 48. And this is in fact true, since the whole shebang derives from CrtpGenr. So the static_casts compile.

But you've got the inheritance thing backwards, methinks. Look at the definition of CrtpGenr:

class CrtpGenr
{
};

It has no methods. Why would you expect the compiler to allow to you try to call one on that object?!

If you cast so that you can put objects of some common base type into a container (e.g. `std::list'), then you can do this, but when you want to call specific methods on that object, you'd need to tell the compiler what kind of object it really is by casting that pointer back to the type you created.

You may want to look into inheritance and polymorphism a little more deeply. For example, perhaps CrtpGenr class can have a virtual method funct1() that the derived classes implement.

Arunas
  • 1,282
  • 1
  • 11
  • 17
  • Yes this casting is done so that I could hold the derived classes in a container. But, for some reason I am not able to cast the crtp_objs to their appropriate Derived classes. Could you please tell me how i may be able to cast back properly. – vixiv Mar 30 '16 at 07:06
  • Thankyou for pointing out "casting that pointer back to the type you created". I have now got the code working the way i want it. – vixiv Mar 30 '16 at 07:58