|
-
June 30th, 2009, 06:16 PM
#1
unresolved externals with templates
I already checked the FAQ and the first 2 solutions did not work.
The third solution worked, but i want to keep my .h and .cpp files seperate, and know why this actualy occurs.
Here is the code:
// header.h
#pragma once
//////////////////////////////
template <class T>
class base
{
protected:
T data;
public:
T getData();
};
// header.cpp
#include "header.h"
//////////////////////////////
template <class T>
T base<T>::getData()
{
return data;
}
// main.cpp
#include "header.h"
#include <iostream>
using namespace std;
void main()
{
base<int> x;
cout << x.getData();
}
-
June 30th, 2009, 07:49 PM
#2
Re: unresolved externals with templates
The implementation of templated code MUST be within (or included within) the header file.
Code:
// header.h
#pragma once
template <class T>
class base
{
public:
T getData() const { return data; }
protected:
T data;
};
P.S. Sorry for the code reconfiguration; I prefer that the public section (i.e. the section I am "advertising") go first; then the protected section, followed by the private section.
-
June 30th, 2009, 09:45 PM
#3
Re: unresolved externals with templates
Actually, it's not entirely true that function bodies of templates must be in the header files, or included in every CPP that uses the template.
This is a common misunderstanding. The importance of this technique isn't that strong anymore, but at one time compilers ran on machines with 64mbytes or less, it was paramount.
The technique is called explicit template instantiation. The linker must find an instantiation of the template matching all type uses of the template. That is, if you use the template on behalf of int and float types, there must be code generated on behalf of both types in at least one object file, so the linker will find them. (You could generate ints in one obj and floats in another, and I've even had to divide a collection of functions for each type in separate obj files, due to memory limitations of the compiler/system at the time - in the early to mid 90's, when 32 Mbytes of RAM was $1,000 - Mbytes, that's not a misprint).
In the "function body file(s)", you must list the explicit instantiations for each and every type you require. Instead of calling the this a "cpp" file, you might use a slightly uncommon extension "inl" - for inline - or "tpl" for template. This is the file that contains the function bodies for the templates.
You create a cpp to instantiate the types involved. Include the header and the "inl" file (you could do this at the tail of the cpp where you have the function bodies), then, issue this for each type:
template TClass< obj >;
where TClass is your template class, and obj is the type of the explicit instantiation.
This creates the code for the indicated type. List each type, and the code will exist in the given obj file for the linker to find.
Back in the day when this was new, Borland had a different syntax for the explicit template instantiation. The one I've listed here worked on GCC 3.x and Visual Studio from at least 2002, and I seem to recall VC6 and VC5 complied.
At one time, years ago, it was all too common for template code to overload the RAM availability during compilation. This technique was useful to localize the template code into various obj files, so as to minimize the impact of templates during compilation. In the current era this isn't all that important, but it can still be used.
Last edited by JVene; June 30th, 2009 at 09:57 PM.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
July 1st, 2009, 02:47 AM
#4
Re: unresolved externals with templates
Is there any place I can read more on what you said JVene?
Somewhere I can see examples of how to exactly implement this?
-
July 1st, 2009, 05:19 AM
#5
Re: unresolved externals with templates
 Originally Posted by JVene
Actually, it's not entirely true that function bodies of templates must be in the header files, or included in every CPP that uses the template.
This is a common misunderstanding. The importance of this technique isn't that strong anymore, but at one time compilers ran on machines with 64mbytes or less, it was paramount.
The technique is called explicit template instantiation. The linker must find an instantiation of the template matching all type uses of the template.
...
I agree with what you have stated, but why would one do this unless they are short of RAM? The whole point of creating a template is to provide reusable code that can work with any object, those that exist today, and possibly those that will be created tomorrow. If you have to define the exact method specializations for each data object that one intends to use with a template, then this would be an enormous task if tens or even hundreds of different objects would be used with the template.
So what you are stating, even though possible, is not practical for larger projects. For small school projects, or perhaps if one is writing code for an embedded system, then perhaps it can be done. Since the OP did not seem aware of how to program with templates, I figure he is either learning C++ at school and working on an assignment, or he is performing entry-level programming at some company.
So hypotheticals aside, what I presented in my first post is typically what is done; an alternative is to separate the header from the implementation in a style shown below. The filename extension of ".impl" which I have used was arbitrarily chosen; yet I was careful not to make it '.cpp' so that a compiler would not mistake it as a file that needed to be compiled on its own.
AnyData.h:
Code:
#pragma once
template <typename T>
class AnyData
{
public:
AnyData(const T& data);
T getData() const;
private:
T data;
};
// Here is where the implementation is included.
//
#include "AnyData.impl"
AnyData.impl:
Code:
// Note that AnyData.h is NOT included!
//
template <typename T>
AnyData::AnyData(const T& data ) : data(data) {}
template <typename T>
T AnyData::getData() const { return data; }
-
July 1st, 2009, 07:06 AM
#6
Re: unresolved externals with templates
...but why would one do this unless they are short of RAM?
Compilation time for one. Of the general objections occasionally raised against the use of templates (with which I don't generally agree), there is the case where when one modifies even a small portion of template code, large sections of the project must be recompiled even though the alteration is a single line. Moving the function body into it's own compilation unit localizes the impact.
The technique is more of a timesaver when developing or working on or debugging template code in larger projects.
As fast as machines are these days, compilers are consuming even more of that power as the language is extended, so the time saving per compilation of a project is similar to what pre-compiled headers can provide in that domain. This results in a time savings when editing code that uses the template, even though template code was not altered.
If you have to define the exact method specializations for each data object that one intends to use with a template, then this would be an enormous task if tens or even hundreds of different objects would be used with the template.
It's actually rather short and simple, it's just a list.
Example, say there's 10 types upon which a template is used.
Code:
// template_unit.cpp
#include "anydata.h" // without automatic include of the impl file
#include "anydata.impl"
#include "otherheaders_for_types.h"
template anydata< type_a >;
template anydata< type_b >;
template anydata< type_c >;
template anydata< type_d >;
template anydata< type_e >;
template anydata< type_f >;
template anydata< type_g >;
template anydata< type_h >;
template anydata< type_i >;
template anydata< type_j >;
That's it.
The tendency, even in very large projects, is that at first this list will have one or two entries, but then it grows incrementally over time, implying that there would be the occasional (and, experience shows it's actually rare) visit to this list to add a type.
Obviously it's more work if one transformed a project to use the technique when it wasn't at first constructed to use it.
Typically the list is grown over a collection or family of templates, which were commonly aided with macros...
MAKE_TEMPLATES( type_a );
...which instantiate a number of templates per type.
So what you are stating, even though possible, is not practical for larger projects.
Don't knock it unless you've used it 
There was a time when you simply couldn't make decent use of templates without the technique. I've been a developer for 30 years, so it's not like I'm making a point purely on theoretical grounds.
However, I am guilty of expounding on a point where the statement, "The implementation of templated code MUST be within (or included within) the header file" is not factually correct, and in most modern work the technique may be of limited benefit.
On the other hand, when crunch time comes, deadlines loom, the project is 4+ million lines of source, and someone touches a template function because a correction is in order - it can actually be of considerable benefit, especially when "cosmic" forces conspire to make that happen repeatedly as an hour or two passes the deadline and the coffee has run out.
The practice of using an implementation file (and I really like the impl extension - hadn't seen that much) is about all the pre-requisite one needs in order to make the practice optional in any project.
That, too, can help deal with "forward declaration puzzles" in template code.
atoMerz, I don't know of anything more detailed than what you see here. Placing the function definitions in a separate file like dwhitney67's suggested "impl" file (I like that extension the more I see it) is the primary key to making the technique possible, after which the example I list above is all there is to instantiating the code.
Last edited by JVene; July 1st, 2009 at 07:13 AM.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
July 1st, 2009, 07:29 AM
#7
Re: unresolved externals with templates
If the template class is to be distributed, it probably should contain entire implemention in header file.
Why? The programmer #including your famous template-class is not concerned where the CPP (or whatsoever extension) resides. He would be less concerned about adding it into the project.
Unless the class has one or more explicit specializations, it's not possible to export the class from a DLL for your DLL clients.
If working in single project; yes, the better idea is to separate them into H and CPP files. But, again, inlining (or non-inlining) may crop up some linker errors!
-
July 1st, 2009, 11:31 AM
#8
Re: unresolved externals with templates
 Originally Posted by JVene
...
It's actually rather short and simple, it's just a list.
Example, say there's 10 types upon which a template is used.
Code:
// template_unit.cpp
#include "anydata.h" // without automatic include of the impl file
#include "anydata.impl"
#include "otherheaders_for_types.h"
template anydata< type_a >;
template anydata< type_b >;
template anydata< type_c >;
template anydata< type_d >;
template anydata< type_e >;
template anydata< type_f >;
template anydata< type_g >;
template anydata< type_h >;
template anydata< type_i >;
template anydata< type_j >;
That's it.
That's pretty nifty.
 Originally Posted by JVene
Don't knock it unless you've used it 
I'll concede to that argument.
 Originally Posted by JVene
The practice of using an implementation file (and I really like the impl extension - hadn't seen that much) ...
I first saw the .impl extension being used when I dabbled with CORBA programming a few years ago.
-
July 1st, 2009, 01:43 PM
#9
Re: unresolved externals with templates
Thanks for the help...
But what I'm actually doing is creating a header file that I can make use of in later projects. So admitting Ajay Vijay if there is anyway to avoid explicit instantiation I wanna know. And I'm sure there is. STL works with all user-defined types, and no instantiation for new types needed.
-
July 1st, 2009, 01:57 PM
#10
Re: unresolved externals with templates
As long as your include list pulls in all of the function bodies before you get to the code that uses it, there isn't a problem.
A few compilers are 'pickier' than others with forward declaration issues inside template code. g++ is tougher on this than Visual Studio, at least prior to g++ 3.4.
If you've placed all the template code in the headers and you're still getting linker errors, post a complete example for us to see.
Incidentally, the explicit instantiation approach can be implemented as an optional use method in distribution and reuse, just conditionally include the implementation using an "ifndef" directive and document.
In any case, unless you have a compilation time issue, a RAM issue, or some other reason the technique is of value, unresolved external errors means "something's missing" in the collection of obj and lib files, and the trick is to make sure it gets them - the "standard" approach simply implies that you've missed a function body or something.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
July 1st, 2009, 02:29 PM
#11
Re: unresolved externals with templates
No I'm sure nothing is missing. I started this as a normal class (not a template class). everything worked just fine. when I tried to do this as a template class errors showed up.
I know that these codes work fine, but I still wanna if there is any other way to avoid explicit instantiation, because for every new type it needs to be rewritten (I know it's just a line of code).
The actual code is long and complicated(at least for myself) but the errors are just like the sample. Again, what I'm looking for is a way to keep my .h and .cpp(or.impl or w/e) seperate and still being able to compile it just fine with arbitrary types without restrictions (i.e. manualy instantiating types, because that's why i wanna use templates)
-
July 1st, 2009, 02:41 PM
#12
Re: unresolved externals with templates
I think you are misunderstanding the fundamentals that have been presented thus far in this thread.
The simplest approach to the issue you are having is to place the implementation of the template class in the header file, either as inline methods or right after the class declaration. If you want to place the implementation in a separate file, then 1) do not include the Header.h file, and 2) make sure that you either include this implementation file in Header.h or follow JVene's example where he defined a "wrapper" file for his template.
Whatever you do, do not name the implementation of your template class with a .cpp extension. You do not want the compiler to compile that file on a stand-alone basis. The file has no context until one provides a type T.
Here's a suggestion if you want separate files...
Header.h:
Code:
// Header.h
#pragma once
template <class T>
class base
{
public:
base(const T d);
T getData() const;
protected:
T data;
};
#include "Header.cpp.impl"
Header.cpp.impl:
Code:
// Header.cpp.impl
template <class T>
base::base(const T d) : data(d)
{
}
template <class T>
T base::getData() const
{
return data;
}
Typical usage:
Code:
// main.cpp
#include "Header.h"
#include <iostream>
int main()
{
base<int> intBaseObject(10);
std::cout << intBaseObject.getData() << std::endl;
}
If you fail to understand the basic example above, then I would suggest that you study JVene's example as an alternate.
-
July 1st, 2009, 03:12 PM
#13
Re: unresolved externals with templates
When the linker says there's an unresolved external, something is missing.
It might not be missing in your visibility, but the linker isn't finding it.
At the risk of repeating what dwhitney67 is saying....
If you rename the file containing the function bodies to *.impl, then issue an include at the tail of your *.h file, that should do it.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
July 1st, 2009, 11:16 PM
#14
Re: unresolved externals with templates
I found the below mentioned link helpful (excuse me if it is repetitive information):
http://www.ecs.fullerton.edu/~sowell...teClasses.html
I use the 2nd option in the above link.
Though I use gcc, I still found the above link relevant and it also explains there is no point in compiling the implementation file for a template.
The above link doesn't talk about the export option, personally I haven't used the export option, so don't know much about it.
-
July 1st, 2009, 11:38 PM
#15
Re: unresolved externals with templates
In that link, the 3rd option uses this syntax:
myClass<int> myClassIntNeverUsed;
myClass<float> myClassFloatNeverused;
myClass<double> myClassDoubleNeverUsed;
For the explicit instantiation, which appears to be what Borland required in the early to mid 90's, creating a global object that's never used.
In my mind, the habit and act of placing the function bodies outside the class declaration is useful if counter intuitive for templates. At least it allows for flexibility in both the notion of compiling template code in a separate obj, which isn't as important now as it once was, and for resolving forward declaration issues some compilers are pickier about in template code.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|