Skip to main content
GameDev.net gamedev.net
🔒 Locked

[C++] Templates

Started by Vanderry Nov 20, 2010 at 5:11 PM 13 replies 2.9k views
Original Post
Vanderry
Vanderry
Hey people !

I was wondering, if I construct a class holding a custom item through template< typename T > and split the class up into a header and source file, do I need to put the template before each of the member function definitions in the source file?


// CFoo.htemplate< typename T >class CFoo{public:	CFoo( T item );	void Process();private:	T m_item;};


// CFoo.cpptemplate< typename T > // Like this?CFoo::CFoo( T item ){ ... }template< typename T > // Like this? Even when there is no occurence of T in the function?void CFoo::Process(){ ... }


I was getting "Error: argument list for class template "CFoo" is missing" for each of the member functions and pasting the template before them seemed to solve the error, but I'm unsure if I've missinterpreted the use of templates :S
stevenmarky
stevenmarky
The definition of your template class should be in your header file, you don't need a .cpp file for that class. Attempting to compile it in the cpp will cause errors.
I find it hard to explain, but the compilation of a template is different to normal compilation - a compiled version of the template is only done when it becomes a concrete type, i.e. CFoo so the whole template definition has to be in the header.

Edit: You might find this useful: Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file (parashift C++ FAQ)

[Edited by - stevenmarky on November 20, 2010 6:25:51 PM]
Vanderry
Vanderry
Hm, okay... So in other words I either can't associate complex functions with classes that hold templated member variables, or I need to put all the defintitions in the header file? Sorry if I'm not getting the point, but I can't help but wonder how STL classes like std::vector work then :/
TheBuzzSaw
TheBuzzSaw
It's just something you have to get used to. Keep templates and inline function definitions in the header file.
Amateurs practice until they do it right.Professionals practice until they never do it wrong.
Vanderry
Vanderry
Quote:
Original post by TheBuzzSaw
It's just something you have to get used to. Keep templates and inline function definitions in the header file.


Okay, I guess that's a bearable restriction. Thanks for the clarification guys !
aryx
aryx
Quote:
Original post by Vanderry
Hm, okay... So in other words I either can't associate complex functions with classes that hold templated member variables, or I need to put all the defintitions in the header file? Sorry if I'm not getting the point, but I can't help but wonder how STL classes like std::vector work then :/

I'm pretty sure the standard containers have their interface and implementation all in the header file. Also, you actually can separate a templated class into header and implementation files, but you need to explicitly instantiate the template for every type you'll be using. I've done this before. An example:

// In templated.hpptemplate <class T>class Templated {   // interface};// In templated.cpp// Implementation here// Template instantiationstemplate class Templated<int>;template class Templated<double>;

I'm far from being an expert, so someone else will have to verify whether or not this works in general, or if it just works for me in GCC. I think it should work in general though, since explicitly instantiating the templates means that the linker will be able to find the the necessary code for any other code that uses those templates.

[Edited by - aryx on November 20, 2010 5:42:05 PM]
rip-off
rip-off
Quote:

I'm far from being an expert, so someone else will have to verify whether or not this works in general, or if it just works for me in GCC.

It works in general.

Quote:

Sorry if I'm not getting the point, but I can't help but wonder how STL classes like std::vector work then :/

The source is included with your compiler. It might be worthwhile looking at - with the caveat that standard headers usually have to jump through hoops to ensure they don't step on any user identifiers. They have to use "implementation reserved" global identifiers (beginning with two underscores, or an underscore and an uppercase letter). They also need to ensure that any user #defines don't stomp on them, so they generally use these ugly identifiers even for member and local identifiers.

Still, the answer to this and many other questions can often be solved by looking at the source, regardless of how ugly it is.
Vanderry
Vanderry
Quote:
Original post by rip-off
Still, the answer to this and many other questions can often be solved by looking at the source, regardless of how ugly it is.


A very good point. I'm sure that would save me a lot of thread-writing, but it's just so therapeutic to ask you guys :) The solution turned into a custom indexing class to be used widely in my applications. C++ is so neat despite its occasional ugliness !
taz0010
taz0010
You can separate the header from the source as long as you #include the source file at the bottom of your header. But you have to give your source file an extension that your compiler won't try to compile into it's own translation unit. Like "Class.inl" or something.
voguemaster
voguemaster
Hi,

To understand this in a better way, you can read the section about "Templates in practice" in C++ Templates: The complete guide. In any case, there are two ways
to write functions as well, inlined to the definition or outside the definition, even on the same header file, like so:

1. inlined:

template
class MyClass
{
public:
T* m_pT;

void foo(T* t)
{
// call some operation on T
t->bar();
m_pT = t;
}
}


2. outside the definition you must name the class with its full name:

template
class MyClass
{
public:

T* m_pT;

void foo(T* t);
}


// now comes the function, notice its preceded by template arguments and MyClass is used as the name of the class it belongs to!
template
void MyClass::foo(T* t)
{
// call some operation on T
t->bar();
m_pT = t;
}



Its not always known but they compiler will freely inline functions if written like in 1, but will less likely do so when written in 2. This can affect your code size considerably since the template's header may be included in many compilation units.

I prefer a standard function call unless I *KNOW* that an inline version will serve me better, otherwise its just a lot of waste.

As for .cpp files - either include them at the end of your header file or don't bother with them. As I said before, check out the book for an explanation, its a good one :)
-----------------------------He moves in space with minimum waste and maximum joyGalactic Conflict demo reel -http://www.youtube.com/watch?v=hh8z5jdpfXY
Red Ant
Red Ant
Quote:
Original post by voguemaster
Its not always known but they compiler will freely inline functions if written like in 1, but will less likely do so when written in 2. This can affect your code size considerably since the template's header may be included in many compilation units.


I thought modern compilers pretty much ignore the 'inline' keyword and just inline when ever THEY think it makes sense to do so.

CmpDev
CmpDev
Quote:
Original post by Red Ant
Quote:
Original post by voguemaster
Its not always known but they compiler will freely inline functions if written like in 1, but will less likely do so when written in 2. This can affect your code size considerably since the template's header may be included in many compilation units.


I thought modern compilers pretty much ignore the 'inline' keyword and just inline when ever THEY think it makes sense to do so.


It depends on the compiler. Visual Studio 10 for example may inline and optimise if it is marked inline yet may not when it is missing. It all depends on how many functions have already been inlined and the magic score VS gives the function.
Katachi
Katachi
Quote:
Original post by Red AntI thought modern compilers pretty much ignore the 'inline' keyword and just inline when ever THEY think it makes sense to do so.


No they don´t ignore them but they are also not forced to use them. Generally the inline definition is just a suggestion to the compiler, not a strict order. They will kindly ignore inline if it does NOT make sense. ;) So it´s just the other way round actually (though surely modern compilers may also choose to make a function inline if appropriate).
Bregma
Bregma
Quote:
Original post by Red Ant
I thought modern compilers pretty much ignore the 'inline' keyword and just inline when ever THEY think it makes sense to do so.


Yes and no.

The inline keyword is overloaded (much like static) and has more than one meaning.

Most compilers will ignore inline when used as a hint on how to generate code.

No compiler will ignore inline when used to annotate a symbol to avoid violation of the one definition rule (ODR). This usage, the one used here, tells the compiler to emit a symbol with appropriate linkage (in the case of ELF binaries, this would be as a weak symbol) so that at link time, the linker will chose one of the symbol definitions as The One. If you do not use the inline keyword in this circumstance, you violate the ODR and the toolchain must emit a diagnostic. Some hint.
Stephen M. Webb
Professional Free Software Developer
voguemaster
voguemaster
Red Ant,

If you look closely at my simple example you'll notice that I didn't use the inline keyword as it isn't needed. In order to satisfy the first example where the method's body is part of the declaration, the compiler will most cases inline that code.

In the second case, you allow it more freedom to inline based on the function and what it does and therefore the compiler is more likely not to inline all the functions.

its just like writing method bodies in the header file inside the declaration or just declaring the methods and at the end of the header file include an .inl file or a .cpp file which is a better approach to inlining.

I read a good source about this a while back but forget where, sorry..
-----------------------------He moves in space with minimum waste and maximum joyGalactic Conflict demo reel -http://www.youtube.com/watch?v=hh8z5jdpfXY

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.