I have a templated "collection" class. I don't wan't the code be recompiled in every source file. But this collection should be used with DataTypes (class SpecialDataMember : DataMember) not defined on definition of the the template class.
This is why I can't force the instantiation in the template source file (throug moving the definitions to the source file and add template LinkCollection<DataMember>;), because the definitions of the template must be accessible in other source files ("SpecialDataMember.cpp").
Is it possible to make "SpecialDataMember.o" hold the code for LinkCollection<SpecialDataMember>. Every includer of SpecialDataMember.h should know I leave LinkCollection<SpecialDataMember> to the linker.
I see two options but I don't know if they work:
Make two template headers (with header guard) one with the definitions one without.
SpecialDataMember.h
// ..
include "LinkCollection.h"
// ..
SpecialDataMember.cpp
// ..
include "LinkCollectionImpl.h"
// ..
include "SpecialDataMember.h"
// ..
template LinkCollection<SpecialDataMember>;
All includers of "SpecialDataMember.h" will not know the definitions of the template so they will let the linker do his work.And the linker will find the instantiation of LinkCollection<SpecialDataMember> in SpecialDataMember.o. Is that correct?
But I would have to maintain two header Files. Is there a better way to gain this effect?
Use template derived classes
If I create a special class SpecialDataMemberLinkCollection : LinkCollection<SpecialDataMemberLink> in the "SpecialDataMember" header and source file, I could reference this special class instead and so the compiler knows there is an instantiation of that class and the base class template and leaves the work to the linker. Will this work as expect?
Is it possible to make "SpecialDataMember.o" hold the code for LinkCollection<SpecialDataMember>. Every includer of SpecialDataMember.h should know I leave LinkCollection<SpecialDataMember> to the linker.
Simple, just put:
extern template class LinkCollection<SpecialDataMember>;
in the header, which tells the compiler not to instantiate that template and leave it to another file.
Then in one SpecialDataMember.cpp file provide that instantiation:
template class LinkCollection<SpecialDataMember>;
Related
I am reading caffe code and find it split C++ class Template code into hpp and cpp files. For example, Net.cpp includes the template class Net implementation code and Net.hpp includes the definition. But I remembered it is not possible to split a template class into hpp and cpp files, how does caffe make this work?
Thank you.
As you noted, template definitions cannot be split up as easily from the declarations without jumping through some hoops.
One common pattern is to split them up in different files for the human reader but essentially they are still defined all in one header. For example
Foo.h
#pragma once
template <typename T>
void Foo(); // declaration
#include "Foo.inl"
Foo.inl
template <typename T>
void Foo()
{
// actual definition
}
Notice that the last thing in the .h file is to actually include the full contents of the .inl file. As far as the compiler is concerned, all of the template definitions are contained in the header to solve the initial problem you mentioned. But to the human reader, the declarations and definitions are separated.
you can not "usually" separate the template definition and deceleration. when the compiler instantiate the template it need to know exactly the definition and the declaration of the members that are used in the context. so if you only include the header file the compiler doesn't know how to instantiate the template for the template parameter.
A solution other than the one that coryKramer mentioned is after the full definition (in the .cpp file) explicitly instantiate the template for the template parameters that you need, this way the template is already instantiated for the values that you would like to use (at this point we have the full declration and definition of template). However, note that if the template is need to be instantiated for other values you may encounter errors as compiler doesn't know how to do this process if the template is not fully defined in that file!
This is the method that is used in caffe via INSTANTIATE_CLASS(Net) macro at the end of .cpp file.
Currently, I am writing a few classes, all of which inherit from a base class and somehow enrich it. All of these classes use templates in order to take different elements as parameters (the classes are all variations of an abstract vector class). So I wrote all of the code in one big .hpp file because I read that splitting the code in .hpp and .cpp would cause linker problems (Splitting templated C++ classes into .hpp/.cpp files--is it possible?) and it wouldn't work.
So I was wondering, since it's not really clean and clear to have everything in a big .hpp file, should I split it and how would I do the splitting the right way in order to keep the code as intact as possible? Should I import the child classes into the base class? Do I have to forward declare all my classes in every .hpp file or not? How would the splitting interact with the templates.
If the code is necessary, I can add it. Just trying to keep it short if it isn't.
As far as splitting the code up, there is a technique for templated code where you can split up the declarations and definitions, at least visually (you'll see why I make that distinction in a moment). So you first start with the header, that will contain just your class and function declarations
Foo.h
template <typename T>
T some_foo(T x); // declaration
#include "Foo.inl"
Then you make a separate file for the implementation. Note that we #include this .inl file in our header, so as far as the compiler is concerned all of the code still exists in the header. Doing it this way is just for human readers, but this way you can split up the actual implementation code into separate files and just include them at the end of the header.
Foo.inl
<template <typename T>
T some_foo(T x) // definition
{
return x + 5;
}
Files:
header.hpp
something1.ipp
something2.ipp
something3.ipp
Content of header.hpp:
#ifndef COMPANY_PROJECT_HEADER_HPP
#define COMPANY_PROJECT_HEADER_HPP 1
#include "something1.ipp"
#include "something2.ipp"
#include "something3.ipp"
#endif
Easy peasy. #include is just a "copy-and-paste" operation so you can do what you like to arrange your files in a pleasing, and easy-to-maintain organisational structure.
All the files are headers, but I've given the "sub-headers" the extension .ipp to distinguish them.
So I wrote all of the code in one big .hpp file because I read that splitting the code in .hpp and .cpp would cause linker problems ... and it wouldn't work.
That only implies that you must not split the definition of the function templates from their declaration (or the definition of member function of a class template from the definition of the template). There is no reason to put the definition of all templates into a single header - which your post seems to imply that you did.
So I was wondering, since it's not really clean and clear to have everything in a big .hpp file, should I split it
Sure.
and how would I do the splitting the right way
Just be sure to keep the definitions of the templates in the same file that declared them - as described in the answers to the linked question. If you think that's messy, then you can put the definitions into another header and include that in the declaring header.
Do I have to forward declare all my classes in every .hpp file or not?
Only in headers that refer to the declarations, but don't need the complete definition.
I am aware that definitions of C++ templated functions have to be placed in header files. However, for reasons of improved readability and structure of a (potentially) big library I am making, I separated the declarations from the implementations, into "mock" headers (which #include the implementation files, quite like this structure of files). Note that am I am aware that the implementation of templated functions must be included at compile time, and I am doing that.
In short, I have a "multiple definition" error when I add a non-templated function declaration into the implementation file. Long explanation with examples follows.
When the pair of "mock" header + implementation files only contain the declaration/implementation pair of the templated function, everything works fine. It also works fine when I add an implementation of a new templated function only in the implementation file.
Working example (I would #include "algo.h" in my main.cpp when I wanted to use this functionality):
"Mock" header file algo.h:
#ifndef ALGO_H
#define ALGO_H
namespace fl{
template <typename Compare>
void algo(.. non-templated args .., Compare order = std::less<int>());
}
#include "tpp/algo.cpp"
#endif // ALGO_H
Implementation file tpp/algo.cpp: (currently just algo.tpp)
Note: Using the tpp/.cpp file was in the initial version, now I am using a .tpp file per #πάντα ῥεῖ's suggestion, explanation in the end.
#ifndef TPP_ALGO
#define TPP_ALGO
#include "../algo.h"
namespace fl{
template <typename Compare>
void subFunctionality(Compare order, .. args ..){ /* impl */ }
template <typename Compare>
void algo(.. non-templated args .., Compare order){
subFunctionality(order, .. args ..);
// implementation
}
}
#endif // TPP_ALGO
The problem arises when I add a non-templated function implementation in the implementation file. (Non-working) example of the tpp/algo.cpp (currently just algo.tpp) (using the same algo.h):
#ifndef TPP_ALGO
#define TPP_ALGO
#include "../algo.h"
namespace fl{
template <typename Compare>
void subFunctionality(Compare order, .. args ..){ /* impl */ }
void moreSubFun(.. args ..) { /* impl */ }
template <typename Compare>
void algo( .. non-templated args ..., Compare order){
subFunctionality(order, .. args ..);
moreSubFun(.. args ..);
// more stuff
}
}
#endif // TPP_ALGO
I get the "multiple definition" error (from where I included it in main.cpp), like so:
obj/Release/main.o In function `fl::moreSubFun(...)':
main.cpp multiple definitions of `fl::moreSubFun(..)'
obj/Release/../tpp/algo.o:algo.cpp first defined here
Why does this happen only to non-templated functions, while it works fine for the templated, and more importantly, how do I solve this problem?
I looked all around SO, and I can't find anything useful :( Ideally, I am looking for something as close to my own file-structure as possible (but I'll take anything that works while still using some separation into "mock" .h + tpp/.cpp). Do I have to take out the additional sub-functionalities into a separate, non-templated pair of .h/.cpp files, or is there other solutions? (The sub-functionalities should ideally not be visible to the end-user).
I am reluctant to use inline when defining fl::moreSubFunc(..) as the function is pretty big (and I was taught inline should ideally only be used with small functions). This does solve the problem, but I'm looking to see if there is a different solution.
I am working in Code::Blocks, using gcc version 4.7.2. This is the initial reason my implementation file is tpp/.cpp (.cpp extension), since Code::Blocks does not support it by default. This is changed in the current implementation following #πάντα ῥεῖ's suggestion (look below).
Late edit (After I taught the solution was found) I taught #πάντα ῥεῖ's answer solves the problem. I tweaked Code::Blocks to accept .tpp files (either treating it as header or source files). Initially, this solution worked.
However, this solution worked only when the algo.h file was included in only one other file: when I included it only in main.cpp. However, as soon as I tried including it in another source file (e.g. algo2.cpp) that would use those algorithms (in addition to main.cpp), the multiple definition problem came back.
Bottom line, the problem still persists as soon as I include the algo.h in more than one file, and I am still looking for a solution.
Your problem occurs because function templates are treated differently at link time from "plain" free functions. Functions must obey the One Definition Rule (ODR); that is, they must be defined in no more than one translation unit. Otherwise, when you get to link time, you end up with multiple definition errors like the one you cited. This same rule also applies to classes, types, and objects in general.
This would seem to preclude the use of templates at all; they must be fully included in every translation unit in which they are used. However, the ODR makes an exception for a few cases. Quoting from Wikipedia:
Some things, like types, templates, and extern inline functions, can be defined in more than one translation unit. For a given entity, each definition must be the same. Non-extern objects and functions in different translation units are different entities, even if their names and types are the same.
This is why you don't run into multiple definition errors with the template functions. At link time, the linker finds the duplicate symbol definitions and removes all duplicates (as long as they are all equivalent; otherwise, this would be an error). Therefore, your program links successfully with exactly one definition of each required symbol.
For your case, your problem occurs because you are including non-template functions in more than one translation unit (everywhere that the .cpp file is included). There would be a few ways of fixing this:
If the template functions are part of a class, you could move the non-template functions to lie in that class as well. This would bring it under the symbol-deduplicating umbrella of the owning template class.
Mark the functions as inline.
Break the non-template functions out into another .cpp file that you then compile separately. That will be the only translation unit that houses them.
In general you should compile .cpp file separately and link it later. But if you want (or must) do it this way, mark all non-template functions as inline. This should help.
As a good rule of thumb:
"Never ever include a .cpp file."
You shouldn't give these template implementation files a .cpp extension. Your build system might include them automatically then.
The conventionally used extensions for such files are e.g. .tcc or .icc. Add these to your project, as you would add other header files.
Don't include them in the project as separately build and linked translation units, if they are used with an #include statement from another header file.
UPDATE:
As you were asking for Code Blocks specifically, you'll just need to tweak your file extension settings a bit, to get these files included in your project correctly, and have them syntax colored as usual:
1. Add the new file type to the file extension settings
2. Add the file type to the project file extension settings Project->Project Tree->Edit file types & categories
As soon a .tcc file is added to the project now, it will be opened using the text editor, and syntax colored as usual:
The corresponding .hpp file looks like this
When we make a class we declare its functions in a header files and define them in a source file... then the header file can be included in the main file to use the class...
But if we declare a template class in header files and define it in the .cpp file and then if we include the header file in the main(containing int main) file then why does a linker error crop up... and the error does not crop up if we included the .cpp file(containing the header file ) in the main file... any answers plz?
Templates don't actually produce any object code at the point where the compiler reads their source code; they're (typically) only "instantiated" when something actually uses the template. So if you define a template function in one source file, and call it from another, the code for the template function doesn't get compiled at all: it's not in the first object file since nothing there needed it, and it's not in the second object file since the compiler didn't have access to the function's definition.
You define template functions in header files so that in each translation unit where something calls the template function, the compiler has access to its code and can compile a copy of it specialized with the appropriate template arguments.
Alternatively, you can use explicit instantiation: you define the template function in a .cpp file, and also tell the compiler exactly which types that it should compile the function for. This is harder to maintain, because you have to keep track of which instantiations are needed by the rest of the program. If something calls foo<float>(), but you've only explicitly instantiated foo<int>() and foo<char>(), you get a missing-symbol error.
You shouldn't #include a .cpp file from another .cpp file. Just put the template function definitions in the header together with their declarations.
A template is neither a class nor a function. Its a pattern that compiler uses to generate classes or functions.
Very nicely explained in HERE
I try to make a generic function in C++, that creating an array of a type which depends on usage (when calling it), like array of int or char.
This is the code in my header file:
template<class T>
T** makeArray(...);
This is in the .cpp file:
template<class T>
T** ClassA::makeArray(...){
//...
}
And this is how I call it in the main file:
char** charArr = cg.makeArray<char>(...);
//...
int** intArr = cg.makeArray<int>(...);
But when compiling, I get these errors:
undefined reference to `char** ClassA::makeArray<char>( ...
undefined reference to `int** ClassA::makeArray<int>( ...
What do the errors mean and how do I fix it?
You have to include the entire body of a C++ template function in the header.
This is because of the way that C++ templates work: template parameter substitution happens only when you actually use the template, and the entire template definition has to be visible at that time. Another way of looking at it is to say that you cannot compile and link to a templateFunction<T>—you can only compile a template function once it's been instantiated as a templateFunction<char> or whatever. For this reason, you cannot put template function definitions in .cpp files, but rather have to put them in .h files.
The compiler needs to have access to the entire template definition (not just the signature) in order to generate code for each instantiation of the template, so you need to move the definitions of the functions to your header.
This is called the inclusion model. Also read this FAQ
In general, you cannot have template definitions in a source file; they should be in the header file so that the compiler can see them.
This comes up over and over again here, so I can't be bothered to give the full explanation again; I recommend you read this from the C++ FAQ: Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?.
[Incidentally, why are you returning a pointer-to-pointer? A pointer should be enough...]
If your code is using the template on a diferent cpp file, the template should go on the header file.