I am a c++ newbie. Today, I have a problem:
in header file, I define a class:
template<class T> class Ptr_to_const {
private:
Array_Data<T>* ap;
unsigned sub;
public:
...
Ptr_to_const<T> & operator=(const Ptr_to_const<T> & p);
};
and in source file, I program as:
template<class T> Ptr_to_const<T>& Ptr_to_const<T>::operator=(
const Ptr_to_const<T> & p) {
...
return *this;
}
when compiled, compiler always say: 'Member declaration not found'.
why?
I use eclipse CDT+Cygwin GCC
thank you very much!
Template classes need to be both declared and defined in the header, or another file which is included by users. They can't be declared in a header and defined in a source file like usual.
The reasoning is that the template must be replaced with an actual type and the source for that generated and compiled when used, and the compiler certainly can't precompile templates for every possible type that may come along, so users need to be able to handle that (and so, need access to the code).
This does cause some issues when passing objects, if multiple libraries include the same templates, as they may be compiled against different versions of the header (see the One Definition Rule).
"Member declaration not found" is an error produced by the Eclipse static analysis tool (codan) rather than compiler. If you get this error, but the compilation succeeds this is a false positive. Older versions of this tool are known to give some false positives, see for example this bug report. So I recommend updating Eclipse CDT to the most recent version. If this doesn't help, submit a bug report to Eclipse CDT.
However, if you get the errors from compiler too (these are indicated by C/C++ Problem in the Type column in the Problems view) then you have probably forgotten to include the header file.
You should include your source file at the end of header file
or you define member function in header file when you define a template class
Related
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
I'm currently writing a logger for my C++ project (I need it to have near to no dependences, so I don't want to take a prewritten one). It contains this function:
template <typename T>
Logger& Logger::operator<<(T f) {
m_file<<f;
return *this;
}
The logger.cpp code compiles, but when I call the log functions in my main.cpp, I have this compiler error:
/home/tuxer/prog/cpp/PRay/server/src/main.cpp:110: undefined reference to `Logger& Logger::operator<< <int>(int)'
for this line of code :
log<<lul; (lul being a int variable equals to 2)
The logger.o file is correctly included, as the Logger::init() function works properly and doesn't raise any linking error.
Thanks :)
Since you have non-inline templates, you need to force instantiation. See for example How do I force a particular instance of a C++ template to instantiate?.
The simple thing to do is to put the Logger::operator<< template in the header file. The compiler will automatically instantiate the versions it needs, and the linker will remove the duplicates (well, at least the ones that weren't inlined).
You shouldn't need to force instantiation unless your linker is old (e.g. gcc 2.7 or earlier).
This is the general rule with template code: put the definitions in the header file unless you have a good reason not to.
See Why can templates only be implemented in the header file? as well.
There are two problems I run into occasionally. One is compile time assertions and the other is a header file being included in multiple places in weird ways (this is not my code so I cannot fix it by not including it in weird ways. Even if I tried, it would take too many hours/days as it is deeply embedded), e.g.:
class Foo
{
public:
#include "VariableDeclarations.h" // Some file that has all the variables that need to be declared
// which is also included by several other classes in the same way
};
The above code is a simplication of what I am currently dealing with. Of course, the class Foo is doing other things as well.
Now if I add another variable declaration to the header in this case, and the file Class Foo is in does not know about the type, I will get a compile error. To fix it, I include the necessary headers. Problem is, all the compiler tells me is "undeclared identifier" and the file name comes up as VariableDeclarations.h. I would like to know which file included the declarations and consequently did not know about the type that I just added.
Similar thing happens with compile time assertions. I have no indication as to which line/file caused the error. It just gives me the error (e.g. in Eigen math library, I was experiencing this a lot).
In g++, you can use the verbose option, -v. For intel, the same flag -v should work. For MSVC there is a project option you can tweak somewhere in one of the build settings: How can I make Visual Studio's build be very verbose?
The preprocessor pound sign (#) has to be the first symbol on the line for it to be processed, and the trailing ; shouldn't be there either:
class Foo
{
public:
# include "VariableDeclarations.h"; // Some file that has all the variables that need to be declared
// which is also included by several other classes in the same way
};
Also, both GCC and MSVC have a switch to only run the preprocessor and show you the generated file. That's an excellent tool to debug this kind of stuff.
I recently ran into the problem described in Weird undefined symbols of static constants inside a struct/class and I am trying to bring my code into compliance by adding definitions to the corresponding .cpp files for all of my static const class members, not just the ones that were causing linker errors.
In the cases where the constant is used in multiple compilation units, I am getting multiple definition errors, even though the definition is only in one of the compliation units.
Moving the initializers to the definitions prevent the errors, but I would rather not do that.
For what it's worth, while I am currently working in Visual Studio, this code needs to build on several platforms.
Static member variables are declared in the class body and defined once outside the class body. The general way of doing this is:
class MyClass
{
static int i;
};
int MyClass::i = 0;
The definition is done in the C++ source files and not in header(.h). If it is done so, the variable will defined everywhere the header file being included. It seems you are facing this very same problem.
If you have language extensions enabled, Visual Studio will allow you to use static const objects without defining the in an implementation file. Unfortunately, it will issue an error (if I remember correctly) for correct C++ programs, when there is an explicit definition.
Try to disable language extensions.
According to one of the posts on http://bytes.com/topic/c/answers/710704-const-static-initialization-visual-studio this may actually be a visual studio bug, preventing you from using that form of initialization.
Unfortunately I think you may be stuck doing the initialization in the source file to maintain portability.
I created a simple example that compiled and linked fine in g++ 4.2.
I think if you want your code to work on multiple platforms, you should move the initialisation to the definition (in the .cpp file). While it might work otherwise on one or more compilers, don't rely on it to be portable.
From what I understand template classes and template functions (for the most part) must be declared and defined in the same header file. With that said:
Are there any other ways to achieve separate compilation of template files other than using particular compilers? If yes, what are those?
What, if any, are the drawbacks of having the declaration and definition in the same file?
What is considered best-practice when it comes to template declaration & definition?
How To Organize Template Source Code
Basically, you have the following options:
Make the template definition visible to compiler in the point of instantiation.
Instantiate the types you need explicitly in a separate compile unit, so that linker can find it.
Use keyword export (if available)
One of the drawbacks encountered by implementing templates in the .h files is that any time you make a small change to the implementation, all the code that uses the template must be recompiled. There's really no way around this aside from not using templates, or declaring & defining them in the CPP file where you use them.
You can implement templates in a seperate file, and then include that file from the .h file. Such as:
templ.h
template<class V> V foo(const V& rhs);
#include "templ.inc"
templ.inc
template<class V> V foo*const V& rhs)
{
// do something...
return val;
}
My personal preference is to implement templates right in the h file unless they become large, and then I'll break it up in to h and inc files.
Not really. The definition of the template must be available at compile time, since templates are instantiated depending on the template arguments you give them. This is why they must be placed in headers, so the compiler can have the code to write a new instantiation. You pretty much need a compiler with support for the export keyword.
People can see your code, if that's a drawback to you. It might also be less "neat" to some people, but I don't think that's an issue.
A further problem is the compile times every time you change the .h (especially if it is included in a lot of places)
Not really. There is the export keyword, but most compilers don't support this. The only mainstream one that I know of that does support this is the Comeau compiler.
If your template is part of a public API then you're exposing your code to the world. (most people don't consider this a problem, but some do. It depends on your business).
Put them both in the same header file.