Sign in to follow this  

The Curiously Recurring Template Pattern help

This topic is 1960 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I cannot for the life of me figure out what im doing wrong. I'm trying to implement CRTP/static polymorphism to avoid the cost of vtable using the following code

[CODE]
template <class Derived>
struct base
{
// some reason this function is not getting called
void implementation()
{
_asm int 3;
static_cast<Derived*>(this)->implementation();
// ...
}
};

struct derived : base<derived>
{
void implementation()
{
_asm int 3;
}
};

int main()
{
derived test;
test.implementation();
return 0;
}
[/CODE]

the problem is it's always calling the derived classes member function without first calling the base class.

Share this post


Link to post
Share on other sites
There's no reason for that code to call the base class' function. The derived function has 'hidden' the base version. Inside main, the compiler has the object '[font=courier new,courier,monospace]test[/font]', which is knows is of type '[font=courier new,courier,monospace]derived[/font]'. When you write '[font=courier new,courier,monospace]test.implementation[/font]' it first looks for that name in [font=courier new,courier,monospace]derived[/font], and finds it. If it didn't find the name there, it would continue looking for it in [font=courier new,courier,monospace]base[/font].

If you instead wrote:[code]derived test;
base<Derived>* polymorphic = &test;
polymorphic->implementation();[/code]Then the compiler only knows that '[font=courier new,courier,monospace]polymorphic[/font]' is of type '[font=courier new,courier,monospace]base<Derived>[/font]', so it looks for the name '[font=courier new,courier,monospace]implementation[/font]' inside [font=courier new,courier,monospace]base<Derived>[/font] first, and calls that function ([i]which then should correctly use CRTP to call the [font=courier new,courier,monospace]derived[/font] version[/i]).

[edit] Also, you're using private inheritance, which hides the base function from public view in derived. Edited by Hodgman

Share this post


Link to post
Share on other sites
so in other words CRTP would be correctly used like the following



[CODE]template <class Derived>
struct base
{
public:
// some reason this function is not getting called
void implementation()
{
_asm int 3;
static_cast<Derived*>(this)->implementation();
// ...
}
};

struct derived : base<derived>
{
void implementation()
{
_asm int 3;
}
};

int main()
{
base<derived> test;
test.implementation();
return 0;
}[/CODE]

I'm still a little confused one one thing. What causes this to be better performance than VTABLE referencing? to me i still see levels of indirection to get to the derived classes function from the base class Edited by nuclear123

Share this post


Link to post
Share on other sites
[quote name='nuclear123' timestamp='1343898131' post='4965452']so in other words CRTP would be correctly used like the following[/quote]No, now your [font=courier new,courier,monospace]static_cast[/font] is completely bogus -- [font=courier new,courier,monospace]this[/font] is not a [font=courier new,courier,monospace]derived[/font], so performing that cast is undefined.
[u]There was nothing wrong with your original version[/u].
[quote name='nuclear123' timestamp='1343898131' post='4965452']What causes this to be better performance than VTABLE referencing? to me i still see levels of indirection to get to the derived classes function from the base class[/quote]They're used for different purposes. Regular virtual functions are for when you need to be able to resolve the polymorphic type dynamically at runtime. Static-polymorphism is used where you can resolve the polymorphic type at compile time.

You can't just take a system that's built around runtime polymorphism and convert it to use compile-time polymorphism. It seems your misunderstanding is based around the purpose of the pattern, not how to implement it.

[edit]To illustrate a use case, consider the code:[code]template<class T> void DoStuff( base<T>& test )
{
test.implementation();
}

derived test;
DoStuff(test);[/code]In the above code, the DoStuff function can be written without knowing anything about the Derived class ([i]including it's header, etc[/i]). It's only when you call the DoStuff function that the polymorphism is resolved (statically, at compile time).

A good compiler will completely optimise out the overhead of the [font=courier new,courier,monospace]base[/font] class, making it as efficient as if DoStuff was calling [font=courier new,courier,monospace]derived[/font] functions directly. The advantage is just in encapsulation / implementation-hiding / good code separation, where DoStuff can be written without any knowledge of the type that it's really operating on. Edited by Hodgman

Share this post


Link to post
Share on other sites
There's no reason to use pointers, references work just fine; for instance:
[source lang="cpp"]
Derived d;
d.interface(); // Prints "Derived implementation"

Base&lt;Derived&gt; & statically_polymorphic = d;
statically_polymorphic.interface(); // Prints "Derived implementation" as well

[/source]
See: [url="http://ideone.com/P7Bmt"]http://ideone.com/P7Bmt[/url]

For more examples to help understand the use, see also:
[url="http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Curiously_Recurring_Template_Pattern"]http://en.wikibooks....emplate_Pattern[/url]
[url="http://eli.thegreenplace.net/2011/05/17/the-curiously-recurring-template-pattern-in-c/"]http://eli.thegreenp...e-pattern-in-c/[/url]
[url="http://accu.org/index.php/journals/296"]http://accu.org/index.php/journals/296[/url] Edited by Matt-D

Share this post


Link to post
Share on other sites

This topic is 1960 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this