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();
🔒 Locked
Template code overhead
Advertisement
Original Post
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?
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.
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.
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?
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?
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.
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.
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.
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.
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.
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.
Quote: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?
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?
Quote: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.
I just can't think of much use for such a thing.
Quote:Emphasis added to a very important word.
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.
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.
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.
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.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement