Sign in to follow this  
Prune

Template code overhead

Recommended Posts

This is very important to me: in the code below, will for each different address used in *t, separate code be generated for the class, and how much--i.e. all functions, or just those that directly reference the template argument (constructor in this case)? What about the base class? Also, what if the template parameter was just used in a data member but no function?
template<Foo *t> class Bar : Base
{
	Foo(void) : Base(t) {}
	SomethingElse(void) {...} // Doesn't use t
};
...
Foo x(...), y(...);
...
Bar<&x> one;
Bar<&y> two[3];
one.SomethingElse();
two[1].SomethingElse();

Share this post


Link to post
Share on other sites
It's up to the compiler.

C++ however has strict policy of: you don't pay for what you don't use. If you never call a templated function, it will not get instantiated. And if you do call it, chances are it will be inlined.

The reason C is preferred by many is because it does not have this non-determinism. In C you know exactly what, how and why. C++ however is a black box.

Test it, check the assembly.

Share this post


Link to post
Share on other sites
Maybe there's a better way to get to what I need. This is related to my question in http://www.gamedev.net/community/forums/topic.asp?topic_id=537055
Base must in all instances be initialized with an *t. Without templates, to make an array of Bar, I'd have to provide an initializer list as in Bar two[3] = {&x, &y, &z} and this works. However, I need two[3] to be a member of a class, which means it must have a default constructor as arrays cannot be initialized in either class declarations or constructor initializations.
This far I figured either to use templates to send the *t to Base, or to make a BarArray type. If I go with templates, my worry is the multiplication of code generated. For BarArray, there's the issue that the internal array cannot be static without templatizing BarArray with the array size (and also seems ugly).
Any better ways?

Share this post


Link to post
Share on other sites
The compiler might generate separate code for each instance, but to me it seems more likely that (in release mode) all the templated function invocations will be inlined anyway, and any separate version would be stripped by the linker. Only one way to find out, though.

As for better ways... IMHO, you should just provide a default constructor that should NEVER BE USED except in that one place. You could even make it private, and friend the owning class. It's ugly, sure... but only in service of getting around C++'s limitations. The time you've spent on it thus far is most likely far greater than any time you'd save from the compiler catching misuses of this sort.

Share this post


Link to post
Share on other sites
Actually I can't even really use the template way because this only works if x and y are global or static, as otherwise their address can't be computed at compile time.

Share this post


Link to post
Share on other sites
So, your original post seems to ask if a different template class will be created for each Foo seated at a different address. Is that the question you are asking?

If that is the case, then no, because an address is not a type. Templates are generated for each type that they are instantiated with.

What will happen, is that if you instantiate this object handing it a foo *, then it will be instantiated for the type "foo *", and for each additional pointer to a type derived from Foo another version of the template will be created.

As the others have said, when a template is used, only those functions that are used with a given type are created by the compiler. beyond that, the compiler may be able to remove some redundant copies -- Once again, C++ has a pretty strict policy of only paying for what you use so most compilers will do their best to reduce redundancy and provide an optimal solution.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ravyne
If that is the case, then no, because an address is not a type. Templates are generated for each type that they are instantiated with.

Templates can be parameterized on both types and pointer/integer constants (and other, similar things).

Share this post


Link to post
Share on other sites
Quote:
template<Foo *t> class Bar

Looks pretty useless. You can only pass pointers to global variables of Foo type with external linkage as parameters.
The code you gave should not even compile.

What are you doing?

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by Ravyne
If that is the case, then no, because an address is not a type. Templates are generated for each type that they are instantiated with.

Templates can be parameterized on both types and pointer/integer constants (and other, similar things).


Right, sorry I've used integers before, and neglected to bring that up... but surely when you have a template parameter of "Foo * f" it isn't creating a new instance of the class for each address supplied, is it? I just can't think of much use for such a thing.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ravyne
Right, sorry I've used integers before, and neglected to bring that up... but surely when you have a template parameter of "Foo * f" it isn't creating a new instance of the class for each address supplied, is it?

It does. Isn't C++ fun? Fortunately modern optimizing compilers and linkers can fold functions with identical contents into single functions, so it's not quite as bad as it used to be.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ravyne
Right, sorry I've used integers before, and neglected to bring that up... but surely when you have a template parameter of "Foo * f" it isn't creating a new instance of the class for each address supplied, is it?
Well, it may have to. What if you took a pointer to the function? How would you store the pointer and the template argument in the space taken by a single global function pointer?
Quote:
I just can't think of much use for such a thing.
See "impossibly fast member function delegates" for an interesting example. But the real answer as to why it's in the standard is that there was no real reason not to allow it; and if it was not allowed explicitly, it would be done in an uglier manner. For instance, if integers had not been allowed as template parameters, you could still pass in integers as template parameters: You'd pass them in as sized arrays, and the template would determine the size of the array. Having a non-ugly way of doing it was judged to be worth it, just in case.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Fortunately modern optimizing compilers and linkers can fold functions with identical contents into single functions, so it's not quite as bad as it used to be.
Emphasis added to a very important word.

Sometimes the details of your code will prevent your compiler from performing the optimizations. Just last month(!) I found a case where two specific dereferences prevented the compiler from that very optimization. Removing them had impacts on both the size of the executable (since we track that) and the speed of the game in that section of code.

If this truly is important to your project, you need to verify that the compiler actually is doing this.

Share this post


Link to post
Share on other sites
I want to thank you guys for the iteresting information.
What I ended up doing is not using templates in my problem as other considerations arose.
I made something between a container and a factory for Bar and that handles the passing of the Foo parameter to Bar's base constructor. I have more code but it allowed me to add other useful functionalities.

Share this post


Link to post
Share on other sites

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