C++: template function instantiation does not work with string as return value. Why?
Hi,
I'm new with templates in C++, but there is something that's really bugging me: I can make references of a template function from one .cpp file in a .h file and use that function in another .cpp file if I instantiate the template with the appropriate types. But when the return type is std::string, linker errors occur. EXAMPLE CODE: main.cpp Code:
#include "template.h" Code:
#include <iostream> template.h Code:
#include <string> Code:
/tmp/ccgjbq5N.o: In function `main': Is there a (practicable) solution for this or do I just have to move templates that won't work like that into header files? |
Well, I am no C++ expert, but I see 'main.cpp' includes 'template.h', and I do not see that 'template.h' includes 'template.cpp'. Nor 'main.cpp' includes 'template.cpp'.
So, if my observation is correct, why do you have 'template.cpp' in the first place ? |
Quote:
This is the usual way to split up code in more than one .cpp file, .h files [=headers] are interfaces between the .cpp files. Here it even works with the template funtions (which are indeed usually just dumped into header files), just the function that returns a string doesn't work that way. As I stated in my first post, everything works as long as I don't use a template function that returns a string. I'm afraid your reply misses the point (if you have further ideas, you are still invited to post them here). One thing I can think of is, the string type seems to be a template itself (the other types aren't), which complicates things. But then I can't find out what the problem is. Maybe that one really is too complicated for me, but I'd rather want to know than to guess. |
The failure to find test<std::string>() is easy to understand.
The definition of test is in a separate compilation unit, so you needed to explicitly instantiate every instance of that which you might use. That is what your code is doing with: Code:
template void test <int> (int); Similarly the failure to find the instantiation of str() needed for str("test"): The compiler has deduced char const* and you simply made the error of providing char* instead. Edit: The momentary brain lapse below was in my original response. But then I realized I had const&T where you have T, which is why the compiler can't misunderstand "test" for you but did for me: Similarly I understand the failure to find the instantiation of str() needed for str("test"). But I don't understand why that almost worked and could be fixed easily. In many places in my own code I have written the equivalent of template <class T> std::string str(T); str("test") and been frustrated that the compiler instantiated something like str<const char[5]> when I really really wanted str<char const*> So I assumed (without knowing where to check in the C++ standard) that template deduction on "test" produces const char[5] instead of char const*. That has made a lot of my code harder to get right. But your error messages show a much better behavior by the compiler. It has deduced char const* and you simply made the error of providing char* instead. |
As the compiler is telling you, you don't haven't instantiated what you need, and the compiler can't do it itself because it can't see the implementations of those templates. Each cpp is a processed by itself, nothing from any other cpp is considered ("Translation Unit").
Just save yourself a lot of trouble and put the implementations into the header file, or include from the header file a "template implementation" file. |
Quote:
|
Quote:
So the information in template.h is known to the compiler during each compile (because it is #included in each). But the information in template.cpp is not know while compiling main.cpp and is usable by main.cpp only through linking (which in g++ is able to connect to already instantiated instances of a template from other compilation units, but is not able to instantiate new instances). |
Quote:
Quote:
|
Quote:
I don't believe you would get the same result. Even fixing just one of the two bugs should have changed the error messages. Repost your code with your understanding of those two corrections and with the error messages if any from recompiling. |
Quote:
So what was the other bug? I read your posts, but I don't see anything besides the "char const*" issue. |
Quote:
|
Quote:
Here is a working version (without string as return parameter), so you get the idea: main.cpp Code:
#include "template.h" Code:
#include <iostream> Code:
#include <string> Compile this with the command "g++ main.cpp template.cpp" or just "g++ *.cpp". Any ideas appreciated I gtg soon, will check on later responses when I'm back at my PC again ;) |
your template should be in the header file.
template.cpp should be template.hpp. template.cpp is not needed. then it compiles. |
Quote:
I know that much. That would be common practice. I'm just wondering why the instantiation method does work with simple types and does not work with the string type (note that I also posted a fully working example). Or rather, I would like to know if it's possible to instantiate template functions that return a string and use them from different .cpp files (or object files or translation units, you get the idea). Again, this does work in the second example I posted, but not when the return type is string. |
Quote:
I also spotted another mistake: the "test" function was not instantiated with the string type. After I added that instantiation, everything worked. johnsfine already explained that in his first post, and I only understood that now. Sorry for that. So everything was just a few mistakes on my part. Thank you for your contributions. The following code works completely, I'm just posting it for convenience: main.cpp Code:
#include "template.h" Code:
#include <iostream> Code:
#include <string> |
All times are GMT -5. The time now is 11:38 PM. |