If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

Re: Why is the CRTP used instead of virtual functions?

Originally Posted by TSLexi

The C++ standard should require compilers to support devirtualization in order to be compliant.

The C++ standard does not require any particular scheme for the implementation of virtual functions, hence it cannot require any particular optimisation pertaining to such implementations. It could require compilers to implement virtual calls as non-virtual calls wherever possible, but that may well be too loose a requirement since "wherever possible" depends on how good the compiler is at the analysis required to determine that such an optimisation can be correctly applied. So, for compilers that lack the implementation of such optimisations, this is not a bug, but rather the lack of a feature.

Re: Why is the CRTP used instead of virtual functions?

that devirtualization case is trivial and has been implemented by compilers for ages. But, devirtualizing all possibly statically resolved virtual calls requires a lot of work from the compiler, especially with the c++ aliasing rules, object and compilation models. So, the best you can ask to a compiler is to being able of devirtualizing "typical" use cases to the extent of making OO the best choice to the avarage programmer ( so, as other said, you don't "need" generic programming techniques, and no I never opposed to OO methodology or any other silly allusion ruzzle claims ). But, if you need tight control on what can be statically resolved (eg. you're a library writer and you want your library components to be used by any programmer with nearly-arbitrary requirements ) then TMP is still the way to go.

sorry if I repeat myself, but CRTP and OO inheritance serve diferent purposes, so it's like asking which is better between a car and a screwdriver; yes, they have a common point of implementing polymorphic behavior, but the list ends here.

on the other hand, if your question is: should I bother with manually resolving polymorphic behavior at compile time ? obviously it depends on your/your potential users requirements (after proper profiling) and obviously most of the time ( and hence in prima facie ) it's not worth it ( furthermore, it depends in the overall design of the code you're working own: clearly, it's easier to find CRTP-like patterns in a generic programming library rather than in an OO design ).

or, if your question is: there exists the theorical need of manually resolving polymorphic behavior at compile time ? IMO definitely yes, because the compiler cannot do everything a programmer can. The point has nothing to do with microoptimizations of virtual calls but it has to do with semantics, has to do with asking the compiler to do his work the best in almost all occasions.

As a concrete example of a non-devirtualizable but statically resolvable code, consider this simple snippet ( off the top of my head, sorry if I missed something )

the compiler cannot prove that D:: p points to a B so devirtualization cannot occur; nonetheless, the <semantics> of D tells us that D:: p must be a B.
Now, this is obviosuly not a realistic example, but situations like that can happen in more complex/real examples as well due to the relatively weak c++ rules laserlight alluded to.

Moreover, the fact that the compiler could in principle prove what the dynamic object of a pointer is, does not imply that the compiler will succeed at proving it, due to time/memory constraints. For example, consider

Code:

A* p = foobar(c) ? new B{} : new C{};
p->foo();

where foobar is an algebraic expression E(c) depending, say, on an integer c provided by user input. Now, we could mathematically prove that E(c) always holds true for every possible c, but the compiler may not be able of proving it in a reasonable time due to intrisic limitations given by the algorithmic complexity it's using. In contrast, if foobar were augmented with domain specific compile time data we could suggest the compiler which algorithm to use to prove that foobar is true in a reasonable time.

Last edited by superbonzo; February 2nd, 2014 at 09:40 AM.
Reason: typos

Re: Why is the CRTP used instead of virtual functions?

Originally Posted by TSLexi

So we've moved from arguing execution speed to arguing compile speed...compile in the cloud for fast compilation, execute on multi-core chipsets for fast execution.

no, I never argued about compilation speed ( the compiler will simply give up an optimization route if it sees the time will explode; so, this has nothing to do with compilation speed, but with the result of compilation, hence execution speed as you call it ); please, reread carefully what I wrote or tell me where I expressed myself wrongly ...

The other is a side effect that works well in a highly controlled environment (like the Java VM and .NET) where 'every' type has an associated runtime type. And makes not so much sense in a language that is less expectant of it's runtime environment.

There are cases of CRTP where "virtual" isn't even at all used.

Originally Posted by TSLexi

When would *you* use CRTP over virtual functions? When your design says that the pointed to object can never be changed at runtime?

Again, no, the "pointed to object" is irrelevant, unless you are using a "side effect" of CRTP in a specific way.

When would I use it... When I have a need for generic class behaviour and there are sufficiently many (many dozens) of classes that the added confusion/complexity outweighs the fact you don't need to repeat the same bits of code in each class.
And in that case, I would also add "it depends who the target audience of said classes are". THe higher end (more experience) the expectancy of your target audience, the easier it is to introduce such idioms.

I understand CRTP, and that it allows smaller class memory representations

NO.
THe amount of generated code will be largely the same. Genericism via templates does not reduce amount of generated code, it only reduces amount of code writte (along with other benefits such as less likely to write errors, ...)

and faster execution speed

More likely than not... this isn't going to make a change.
If you CRTP a virtual function it'll still be a virtual function. If you CRTP a non-virtual, the end result is the same non-virtual.

There is a change devirtualization might make a change, but again... this won't matter much in C++

And with modern compiler optimizations like devirtualization, virtual functions should be as fast as CRTP

Mmmm... no. See next.

And it's even less attractive now that devirtualization optimizations are coming of age for C++. The compiler simply removes dynamic dispatches whenever possible.

What surprises me is that it took so long. Java has had it for ages. Either it's because old C++ programmers so desperately need slow virtual calls to substantiate their critical view of OO, or it's because competition between compiler suppliers isn't working so no one is willing to put money into improvements.

1) Yes, compiler have become smarter in removing unnecessary calls to a virtual if the compiler can establish the precise type and can thus call the function directly rather than using the 'virtual mechanism' (not all compilers use vtables for this).

2) The problem is worse on java where the code is interpreted by the VM (or runtime compiled), and the type is dynamic so there's a much bigger runtime cost than a simple "vtable lookup and call through pointer" of native C++ code running on actual hardware.
So there has been less need to try and solve this for C++ because the difference between a direct call and a virtual call is immeasurable.

The above is especially true with the "base address randomization" feature which basically changes all calls to indirect calls anyway, so the difference between a "regular" function call and a virtual function call is even less.

If you really have a case where the difference between regular/virtual call would actually matter (as in a noticable part of the CPU time is going into the call itself), then the real issue is the call/return itselfr and not the regular/virtual nature of said call.

Re: Why is the CRTP used instead of virtual functions?

It would appear you don't quite understand CRTP just yet. Maybe just a particular sub-aspect of it when used in the specific case with virtual functions (a very narrow view at CRTP as a whole).
CRTP is not only about virtuals. You can also make a CRTP template with regular member functions or static functions
or... The purpose is genericism in class behaviour.
The specific end-behaviour can be static, virtual, or can be derived from template specialization or a combination of multiple/all of these.

Re: Why is the CRTP used instead of virtual functions?

Originally Posted by OReubens

If you really have a case where the difference between regular/virtual call would actually matter (as in a noticable part of the CPU time is going into the call itself), then the real issue is the call/return itselfr and not the regular/virtual nature of said call.

Just thought about this, but oddly enough... CRTP can be a way to actually solve this issue by avoiding the function call entirely (replacing it with a inline) at the cost of runtime code duplication (which would be the solution anyway) without the actual C++ code duplciation.

The above generates 1 billion calls to a virtual function. Since the virtual function itself is small, the overhead of the actual call is significant.

Now consider a CRTP approach where you templatize the func_using_Calc_many_times() and CRTP it so you can easily duplicate the entire function in all your classes, but instead of a virtual, since the call is now part of the class, it can be optimized to an inline. You will get a full implementation of the function in each class rather than 1 generic function calling to many virtuals. So this'll take more code, but be faster since it saves the virtual while conceptually still offering the same dynamicism.

Trying the above on my PC.
the virtual solutions runs in 6.5 sec
the CRTP solution runs in 5 sec
Which is a 23% improvement. For an even simpler Calc() this would be more prominent. 23% might be significant.
But how many times is your virtual function called 1 billion times. Except for this "enforced" example, the 1.5sec difference will not be noticable.

Or as a conclusion, CRTP can be a means to remain having generic code without the virtual call overhead.
THat doesn't mean all cases of CRTP are doing exactly what's happening here. Again, this is 1 specific case where CRTP can be used to do something (in this case: automate code repetition/duplication in each derived class to get as sideeffect that you remove a call entirely by allowing the compiler to inline a static).

Re: Why is the CRTP used instead of virtual functions?

Originally Posted by superbonzo

sorry if I repeat myself, but CRTP and OO inheritance serve diferent purposes, so it's like asking which is better between a car and a screwdriver; yes, they have a common point of implementing polymorphic behavior, but the list ends here.

No.

Polymorphism is polymorphism and it serves the purpose of polymorphic behaviour regardless of when it's resolved, be it at compiletime or runtime.

The only difference is that the CRTP (used to simulate OO inheritance) is resolved at compiletime since it's a template pattern, whereas ordinary OO inheritance (using virtual functions) is resolved at runtime. Unless, that is, devirtualization optimization can be applied to the latter. Then they're equivalent and you can replace CRTP with OO inheritance. It won't change the semantics or meaning of your code. The compiler output will be equivalent, even identical.

I'm no stranger to making things faster by resolving things at compiletime by it's not a design issue. The C++ template system is a form of generics and that's not the same kind of polymorphism as OO inheritance. I know that but the difference is not when the polymorphisms get resolved.

If you dropped this artificial rift between compiletime and runtime you wouldn't be so confuddled.

Re: Why is the CRTP used instead of virtual functions?

Originally Posted by razzle

whereas ordinary OO inheritance is resolved at runtime.

This is flat out wrong. It is resolved at compiletime just the same way. That's why C++ has strictly typed. it's the compiler that decides it will call a member through a v-table (or some other mechanism) or whether it can definitely decide that it can call the member directly.
Runtime has nothing to do here.

Again I fear the point about CRTP is lost somewhere. CRTP is not "an alternative solution to replace virtuals". It can sometimes be used as such, but that's not really what it's about.

virtual members are an important part of (dynamic) polymorphism
CRTP is a means to automate class genericism, this genericism may have nothing to do at all with polymorphism. Though admittedly static polymorphism is an obvious use of CRTP.

Re: Why is the CRTP used instead of virtual functions?

Originally Posted by OReubens

This is flat out wrong. It is resolved at compiletime just the same way. That's why C++ has strictly typed. it's the compiler that decides it will call a member through a v-table (or some other mechanism) or whether it can definitely decide that it can call the member directly.
Runtime has nothing to do here.

No you are wrong. The call of a virtual function is not resolved (or bound as it's also called) at compiletime. The type checking can be performed at compiletime unless a downcast is involved. But the call itself is resolved at runtime by way of a so called dynamic dispatch. That's why it takes a little longer than a non-virtual call.

Again I fear the point about CRTP is lost somewhere. CRTP is not "an alternative solution to replace virtuals". It can sometimes be used as such, but that's not really what it's about.

Nothing is lost. Have a look again at the title of the thread.

virtual members are an important part of (dynamic) polymorphism
CRTP is a means to automate class genericism, this genericism may have nothing to do at all with polymorphism. Though admittedly static polymorphism is an obvious use of CRTP.

No.

CRTP is a template pattern that can be used to simulate OO polymorphism (virtual functions) at compiletime. That's the usage we're talking about here.

My point is that with devirtualization enabled, CRTP will be nothing but a premature optimization. The compiler will optimize your ordinary OO polymorphic code to do exactly what you thought you needed CRTP to accomplish.

* The Perfect Platform for Game Developers: Android
Developing rich, high performance Android games from the ground up is a daunting task. Intel has provided Android developers with a number of tools that can be leveraged by Android game developers.

* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.