guys, this is my first question in StackOverflow so forgive me if make any mistake.
I am writing a small project which contains 2 source files and 3 header files.
// some_template_functions.h
#ifndef SOME_TEMPLATE_FUNCTION_H
#define SOME_TEMPLATE_FUNCTION_H
template <typename T>
int getvalue(string line, string key, T & val)
{
// method to get value (all the types except string) from line using key
}
template <>
int getvalue<string>(string line, string key, string &val)
{
// method to get some string from line using key, similar to getvale<int>
// but with slight difference to handle some special characters
}
#endif
//myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include "some_template_functions.h"
class MYCLASS
{
//declarations of constructors, member functions and members
double member_double;
string member_string;
}
#endif
//myclass.cpp
#include "myclass.h"
MYCLASS:MYCLASS()
{
// for each member
// using "getvalue" defined in "SOME_TEMPLATE_FUNCTION.H" to get the values
getvalue(line, key, member_double);
getvalue(line, key, member_string);
}
//main.cpp
#include "myclass.h"
#include "some_template_functions.h"
int main()
{
myclass A;
int some_value;
getvalue(line, key, value);
return 0;
}
I have no problem compiling the main.o and myclass.o but it is just when I was trying to link the two object files I got error message like:
myclass.cpp: multiple definition of int getvalue<std::basic_string><char, std::char_traits<char>, ...> and etc.
/tmp/cc22zEow.o:main.cpp: first defined here
collect2: ld returned 1 exit status
I know the reason probably is because I am including "some_template_function.h" in both myclass.h and main.cpp, each myclass.o and main.o is going to have its own definition of getvalue which is causing the problem. If I change
#include "some_template_functions.h"
to
#ifndef SOME_TEMPLATE_FUNCTIONS_H
#define SOME_TEMPLATE_FUNCTIONS_H
#endif
the constructors of MYCLASS is not goint to work.
I plan to expand the "some_template_functions.h" and its .cpp file in the future so if possible I would like to keep them separated from the other files. And because the way I am declaring function "getvalue" my attempt to move its definition to .cpp file was not working out for me very well.
I've tried to solve this problem for days but since I just start to learn C++ so far I could not get this right. So please, any suggestions will be appreciated! Thanks in advance!
The specialization of getvalue<std::string>(...) isn't a template and, thus, not implicitly inline. If you want to define this function in a header, e.g., because it is close to trivial and should be inlined, you'll need to mark it explicitly as inline. If the function does anything non-trivial it may be worth merely declaring the specialization in the header and defining it in a suitable translation unit.
Related
I am currently working on a project where we have a shared set of headers. Now we want add some private fields without having to put those declarations directly in the shared headers.
Someone brought up the following:
namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#if __has_include("foo_private.hpp")
#include "foo_private.hpp"
#endif
};
}
Inside the _private.hpp headers we would then place the private fields for that class. When there are only default datatypes (int, bool, etc) this works fine(ish). But as soon as you put an include inside the _private.hpp file, for example #include everything breaks.
It is giving the following error expected unqualified-id before ‘namespace’ which as I understand is quite logical, since you're trying to define a namespace inside of a class.
Example _private.hpp file
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
Now my question is, is there any way to trick the preprocessor, or somehow get the same results with a different solution?
namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#if __has_include("foo_private.hpp")
#include "foo_private.hpp"
#endif
};
}
If that code is including a file that looks like this:
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
Then you end up with this (though in reality, the #includes themselves would resolve to the contents of <string>, etc.):
namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
};
}
Perhaps that shows your issue? You're including "string" in the middle of your class, but it needs to be included at the global namespace scope of your file.
Instead, include string at the top of the outer header, don't use include guards in the private header, and only put the body of the code you want pasted into your class into that private header. For that reason, you might not call it a ".hpp" file but something else to make it clear it's not a normal header.
Additionally, the __has_include feature seems dubious, because if your private header is missing you probably do not want it to compile to an empty class.
Worse, if you compile some translation unit that finds the header, and then compile another translation unit that does not find the private header, you will end up with two different definitions of your class, violating the One Definition Rule -- which is undefined behavior, no diagnostic required. Really nasty stuff (assuming your builds succeeds at all.)
I'm not a big fan of this kind of hiding, as it will make it hard for editors to properly show your code, to colorize and index your private header, or otherwise work with the code in a normal way. You might consider looking at the PIMPL idiom for hiding the implementation of a class in its .cpp file, so users of the header do not have to see it at all.
I'm trying to create a library for a school work, and I've been wondering if it is safe to declare a templated class on the main header file containing the class definition and method declarations, but then separating the method definitions in a different header file?
Because I have been able to do this in my example below, but I don't know if it will cause me some problems in the long run.
main program
// main.cpp
#include <iostream>
#include "declaration.hpp"
int main()
{
card<int> a(5);
std::cout<<a.getID()<<'\n';
return 0;
}
main header file
in this header file, only the class definition and the declaration of the method getID() is written but not it's definition, and by the end of the class I included the other header file that contains the method definitions.
// declaration.hpp
#ifndef DEC_HPP
#define DEC_HPP
#include <iostream>
template<typename T>
class card
{
public:
T id;
card(const int id) : id(id) {}
T getID();
};
#include "definition.hpp"
#endif
method definitions
This header file contains the method definition of getID() from the main header.
I also included the "declaration.hpp" in this header, and this is the part where I'm not so sure of, because I included both files together with each other.
// definitions.hpp
#ifndef DEF_HPP
#define DEF_HPP
#include <iostream>
#include "declaration.hpp"
template<typename T>
T card<T>::getID()
{
return id;
}
#endif
I have compiled this program and it's working on my machine, but I just wanted to know if this way of isolating my code will cause me some errors in the future, I don't want to put my templated class definitions in a cpp files because I find it hard to maintain.
This is indeed a better approach because it makes your code look simple and better. Moreover, it is the main reason why header file is used.
Your main header file will simply tell that what functions/classes are you using and without even viewing your code, anyone can guess if you are working correctly or not.
There wont be any safety issues at all.
This question already has answers here:
multiple definition in header file
(4 answers)
Closed 4 years ago.
I just can't get my head around why this won't compile.
I have three files:
main.cpp
#include "expression.h"
int main(int argc, char** argv)
{
return 0;
}
expression.h
#ifndef _EXPRESSION_H
#define _EXPRESSION_H
namespace OP
{
char getSymbol(const unsigned char& o)
{
return '-';
}
};
#endif /* _EXPRESSION_H */
And expression.cpp
#include "expression.h"
(Ofc there is more inside of it, but even if I comment everything except for the #include out it doesn't work)
I compile it with
g++ main.cpp expression.cpp -o main.exe
This is the error I get:
C:\Users\SCHIER~1\AppData\Local\Temp\ccNPDxb6.o:expression.cpp:(.text+0x0): multiple definition of `OP::getSymbol(unsigned char const&)'
C:\Users\SCHIER~1\AppData\Local\Temp\cc6W7Cpm.o:main.cpp:(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
The thing is, it seems to parse expression.h two times. If I just compile it using main.cpp OR expression.cpp I don't get the error. The compiler just ignores my #ifndef and continues...
Any clues?
The thing is, it seems to parse expression.h two times.
Of course it does. You include it in two different cpp files. Each inclusion dumps the content of the header into that translation unit, so you get two definitions of the same function, making the linker rightfully complain. This has nothing to do with include guards, which protect you from accidentally including twice in the same file.
You can, however, have a function defined in a header. So long as it's marked inline. So do this:
namespace OP
{
inline char getSymbol(const unsigned char& o)
{
return '-';
}
}
inline here is a promise that all of those functions are the exact same one, to the letter. So the multiple definitions are in fact considered one and the same. Be careful not to break this promise however (don't use any construct that can change the function body depending on where it's included).
And by the way, a namespace doesn't need to be terminated with a ;, so I took the liberty of removing it.
I have a struct Tree that is defined inside Class Parser. I have methods defined in Parser that take Tree as input.
void Parser::InputTree(const Tree& input) {
//uses data from Tree
}
Everything seemed to be working fine. But then I needed to use Tree outside the class. So I decided to define struct Tree in a separate header. I included this header in the header file for Parser. While I see no errors in the header file of Parser, the source file shows errors on my Eclipse. Says member declaration not found pointing to method InputTree.
My question is, first off is this the right strategy to define a struct in a separate header? Second, what am I doing wrong? Third, I have some enum types also that I want to use across classes. Where do I define it?
Right structure:
parser.h
#ifndef _PARSER_H_
#define _PARSER_H_
#include "tree.h"
class Parser {
void InputTree(const Tree& input);
};
#endif /*_PARSER_H_*/
parser.cpp
#include "parser.h"
void Parser::InputTree(const Tree& input){
// use data from Tree
}
tree.h
#ifndef _TREE_H_
#define _TREE_H_
struct Tree {
//nodes
};
#endif /*_TREE_H_*/
Including parser.h includes tree.h and hence, struct Tree is available in the main compilation unit.
A simple rule of the thumb I usually follow, is if a custom datatype (i.e. struct, enum, etc.) is used only within a class, I end up defining this datatype within the definition of the class.
But if the same type is required to be used across 2 or more classes (without any parent-child relationship), I end up defining the type either within another header file and usually within a namespace (when the types or related in some fashion).
And yes you could use multiple such namespaces within multiple header files (to group related types), if you feel the need to distinguish them, but I've just show a simpler example using a single namespace:
/* MyNamespace.h */
#ifndef MY_NAMESPACE_H
#define MY_NAMESPACE_H
namespace MyNamespace {
struct Tree {
int a;
char b;
};
enum SomeEnum {
VALUE_0 = 0,
VALUE_1 = 1,
VALUE_2 = 2
};
}
#endif
/* Parser.h */
#ifndef PARSER_H
#define PARSER_H
#include "MyNamespace.h"
class Parser
{
public:
void InputTree(const MyNamespace::Tree& input);
};
#endif
/* Parser.cpp */
#include "Parser.h"
void Parser::InputTree(const MyNamespace::Tree& input)
{
}
Yes, it is a correct strategy to define the struct in a separate header file.
What you are doing wrong is hard to say without more input - but it probably has to do with includes, include-guards or namespace mismatches.
And finally, you should declare the enums in another header file, with proper include guards.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why can templates only be implemented in the header file?
I've struggled with this for a while, and I've taken a look to several questions here, but being new to C++ I haven't been able to understand where I am wrong.
Here is the code, I took it from this page and tried to make it work, but so far I haven't been lucky:
stack.h
#ifndef STACK_H
#define STACK_H
template <class T>
class Stack {
public:
Stack(int n);
~Stack() { delete[] s; };
private:
T* s;
int _top;
int _size;
};
#endif // STACK_H
stack.cpp
#include "stack.h"
template <class T>
Stack<T>::Stack(int n) {
_size = n;
_top = -1;
s = new T[_size];
}
main.cpp
#include <iostream>
#include "stack.h"
using namespace std;
int main() {
Stack<int> s(10); // undefined reference to `Stack<int>::Stack(int)'
return 0;
}
When I compile (gcc 4.5.2) I get one error: undefined reference to Stack<int>::Stack(int). I've tried several things but without any real knowledge to support what I do. I will be really thankful if somebody can explain me what's going on.
You can only have a template class definition in a cpp file if it's a specialized definition - i.e. you know what T is.
Other than that, and your case belongs here, all definitions of your template class have to go in the header file. The compiler has to know about these each time a new instance is declared or defined because the type, and thus the behavior, changes. Definitions in a cpp file would mean a different translation unit, so the compiler couldn't possibly know about the behavior for every single T you try to apply to your template.
There is nothing to compile in "stack.cpp". Templates are only compiled when they are instantiated. Hence the linker cannot find this function which was never compiled.
You can't really separate declarations and implementations in header and source files with templates.
What you can do is copy-n-paste "stack.cpp" to the end of "stack.h". Alternatively include "stack.cpp" at the end of "stack.h", not the other way round, which achieves the same effect. In the latter case it might be wise to change the extension of the "cpp" file (see Including .cpp at end of template header file)
The compiler has to have all of the pertinent information when creating template classes and consequently templates are generally fully implemented in their header files.
There are several ways you could accomplish this, inline functions, defining the template functions in the header file, including your implementation in a separate file (at the end of your header file, with #include), etc.
Here's a similar question with more details.