I can't figure out why the code does not compile, even when I have the include guards to prevent repetitive compilation
The main class foo.h:
#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED
#include <iostream>
class Foo;
template<int TDim>
struct Foo_Helper
{
static bool Compare(const Foo& this_foo, const Foo& other_foo);
};
class Foo
{
public:
Foo(const int& Value) : mValue(Value) {}
virtual ~Foo() {}
const int& Value() const {return mValue;}
template<int TDim>
bool Compare(const Foo& rother_foo) {return Foo_Helper<TDim>::Compare(*this, rother_foo);}
private:
int mValue;
};
#endif
#include "foo.hpp"
foo.hpp to define the template specialization:
#ifndef FOO_HPP_INCLUDED
#define FOO_HPP_INCLUDED
template<>
bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo)
{
return this_foo.Value() == other_foo.Value();
}
template<>
bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo)
{
return this_foo.Value() == other_foo.Value();
}
#endif
The two source files:
src1.cpp:
#include "foo.h"
class Test1
{
public:
bool test()
{
Foo f1(1);
Foo f2(2);
return f1.Compare<1>(f2);
}
};
src2.cpp:
#include "foo.h"
class Test2
{
public:
bool test()
{
Foo f1(1);
Foo f2(2);
return f1.Compare<2>(f2);
}
};
CMakeLists.txt:
set(file_list
src1.cpp
src2.cpp
)
add_library(Test SHARED ${file_list})
The error messsage:
Linking CXX shared library libTest.so
CMakeFiles/Test.dir/src2.cpp.o: In function `Foo_Helper<1>::Compare(Foo const&, Foo const&)':
/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:7: multiple definition of `Foo_Helper<1>::Compare(Foo const&, Foo const&)'
CMakeFiles/Test.dir/src1.cpp.o:/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:7: first defined here
CMakeFiles/Test.dir/src2.cpp.o: In function `Foo_Helper<2>::Compare(Foo const&, Foo const&)':
/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:13: multiple definition of `Foo_Helper<2>::Compare(Foo const&, Foo const&)'
CMakeFiles/Test.dir/src1.cpp.o:/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:13: first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [multiple_definition_error/libTest.so] Error 1
make[1]: *** [multiple_definition_error/CMakeFiles/Test.dir/all] Error 2
make: *** [all] Error 2
I thought the inclusion guard has prevented the two functions in foo.hpp to be compiled. However, it looks like that each cpp file compile its own functions. In this case, how to properly define the template specialized functions?
The header guards stop the header being included twice in the same translation unit. Your problem is that the definitions of the Compare specializations will be defined in two translation units, but are not marked inline. This means that when the linker tries to link the object files produced by test1.cpp and test2.cpp, it gives you a multiple definition error. If you mark the specializations as inline then they can be defined in two TUs and the linker will just throw away one of the definitions:
template<>
inline bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo)
//^^^^
{
return this_foo.Value() == other_foo.Value();
}
template<>
inline bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo)
//^^^^
{
return this_foo.Value() == other_foo.Value();
}
You can also put specialization code in .cpp. I think it may be the best solution since specialization (usually) is closely related to the newly created classes (Test1 and Test2).
Alternatively put
template<>
bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo)
{
return this_foo.Value() == other_foo.Value();
}
template<>
bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo)
{
return this_foo.Value() == other_foo.Value();
}
into foo.cpp (instead of foo.hpp) and in foo.hpp only say that specialization is "extern".
Additionally you should move class declarations from src1.cpp to src1.hpp ;)
Related
I have the following project structure:
This a handler for the "IOPin" class:
//IOPinHandler class
//IOPinHandler.h
#include <type_traits>
class IOPin; //forward declaration required
class IOPinHandler
{
public:
explicit IOPinHandler() { }
virtual ~IOPinHandler() { }
void checkBool(const bool& b);
void checkInt(const int& b);
template<typename T>
void modifyIOPinMember(IOPin& ioPin, const T& param);
};
//To avoid multiple definitions
#ifndef _OD_
void IOPinHandler::checkBool(const bool& b)
{
//Do stuff
}
void IOPinHandler::checkInt(const int& b)
{
//Do stuff
}
#endif
The following is the .tpp file for the definition of modifyIOPinMember member.
//IOPinHandler class
//IOPinHandler.tpp
template<typename T>
void IOPinHandler::modifyIOPinMember(IOPin& ioPin, const T& param)
{
if constexpr(std::is_same_v<T, int>)
{
checkInt(param);
ioPin.m2 = param;
}
else if constexpr(std::is_same_v<T, bool>)
{
checkBool(param);
ioPin.m1 = param;
}
}
The following is the "IOPin" class, the one meant to be handled by the class above. Since IOPinHandler's modifyIOPinMember member requires to know the definition of "IOPin" (its complete type) then, the IOPinHandler.tpp file is included in IOPin.h file as follows:
//IOPin class
//IOPin.h
//To avoid multiple definitions
#define _OD_
#include "IOPinHandler.h"
class IOPin
{
public:
explicit IOPin(const bool& b, const int& n):m1(b), m2(n) { _handler = new IOPinHandler; }
void setInt(const int& n) { _handler->modifyIOPinMember(*this, n); }
void setBool(const bool& b) { _handler->modifyIOPinMember(*this, b); }
private:
bool m1{false};
int m2{0};
IOPinHandler* _handler{nullptr};
friend class IOPinHandler;
};
#include "IOPinHandler.tpp"
The problem is that calling either setInt or SetBool methods, result in a compile time error:
//main.cpp
#include "IOPin.h"
IOPin a(false, 0);
int main()
{
a.setInt(89);
a.setBool(true);
return 0;
}
This is the error:
/usr/bin/ld: /tmp/ccpKv7HW.o: in function `void IOPinHandler::modifyIOPinMember<int>(IOPin&, int const&)':
main.cpp:(.text._ZN12IOPinHandler17modifyIOPinMemberIiEEvR5IOPinRKT_[_ZN12IOPinHandler17modifyIOPinMemberIiEEvR5IOPinRKT_]+0x27): undefined reference to `IOPinHandler::checkInt(int const&)'
/usr/bin/ld: /tmp/ccpKv7HW.o: in function `void IOPinHandler::modifyIOPinMember<bool>(IOPin&, bool const&)':
main.cpp:(.text._ZN12IOPinHandler17modifyIOPinMemberIbEEvR5IOPinRKT_[_ZN12IOPinHandler17modifyIOPinMemberIbEEvR5IOPinRKT_]+0x27): undefined reference to `IOPinHandler::checkBool(bool const&)'
collect2: error: ld returned 1 exit status
What am I missing over here?
I know that a solution is to create a "IOPinHandler.cpp" file and put there the definitions for "checkBool" and "checkInt" methods, however I dont want to have a separate .cpp file only for that.
Thanks in advance.
In C++, we almost never include the implementation file, only header (.h) files; and, if your class is templated, all class's function implementations should be in header only; no secondary file is needed or advised, and you should always use header guards for your header files, used as follows:
#ifndef ANY_UNIQUE_NAME // recommended related to header file name
#define ANY_UNIQUE_NAME
//#includes <...>
//header code
#endif
Then you include headers when you need them.
I have two classes : Individu and Cite and as u can see Individu is defined before
//file.hpp
#include <iostream>
#include <stdexcept>
#include <vector>
extern Cite CITE;
class Individu {
protected:
static int id;
TYPE t;
public:
Individu();
virtual ~Individu();
static int & getCompteur();
virtual void afficher(std::ostream& ) const;
virtual TYPE getType() const;
};
class Cite {
std::vector<const Individu *> tab;
public:
Cite();
~Cite();
void addPersonne(const Individu *);
int size() const;
};
std::ostream& operator<<(std::ostream&, const Individu& );
#endif
I need to add an Individu one it's instanciated to the tab vector of Cite and sisnce there is just one Cite I declared Exctern CITE Cite to work with just like that :
// file.cpp
#include <algorithm>
#include "file.hpp"
int Individu::id = 0;
Individu::Individu() {
CITE.addPersonne(*this);
id++;
}
Individu::~Individu(){
}
int& Individu::getCompteur() {
return id;
}
void Individu::afficher(std::ostream& o) const{
o << id;
}
void Personne::afficher(std::ostream& o) const {
o << nom << " " << id;
}
std::ostream& operator<<(std::ostream& o, const Individu& i ){
i.afficher(o);
return o;
}
TYPE Individu::getType() const {
throw IllegalException();
}
Cite::Cite(){
}
Cite::~Cite() {
}
void Cite::addPersonne(const Individu * i){
tab.push_back(i);
}
int Cite::size() const {
return tab.size();
}
and when I compile I got this error :
file.hpp:13:8: error: ‘Cite’ does not name a type
13 | extern Cite CITE;
| ^~~~
file.cpp: In constructor ‘Individu::Individu()’:
file.cpp:30:5: error: ‘CITE’ was not declared in this scope
30 | CITE.addPerconne(*this);
| ^~~~
make: *** [makefile:15 : build/deviant.o] Erreur 1
I understand that Cite is not yet defined so that's why I got that error , so hwo can I fix it ?
You have two issues in your code:
extern Cite CITE is declared before the class Cite is defined, so the compiler doesn't know what a Cite is at that point. You should move this declaration after the definition of Cite.
You never define CITE. An extern variable declaration is a promise to the compiler that you will define that variable later. You're essentially saying "I promise a Cite object named CITE exists even though you can't see it right now". You broke that promise by never actually creating that object. You need to define a Cite CITE somewhere (most likely in file.cpp).
I have a class, and within that class I define a struct. The struct has overloaded comparison operators so that it can be used with a map (with an int as the key).
Prior to messing with classes, I had the struct defined in a .cc file, and that file also contained a function which returned a map of this struct. It worked.
Now I want to have the struct defined in the class header, and the class should have a function which returns a map of structs.
Here is a simplified version of my code, which compiles with the same error as the full version. I don't understand the error, and would appreciate any help!
Cheers.
myclass.h:
#include <map>
class myclass {
public:
struct mystruct {
int i;
mystruct();
mystruct(int j);
bool operator==(const mystruct& rhs);
bool operator>(const mystruct& rhs);
bool operator<(const mystruct& rhs);
};
::std::map<int,mystruct> getStructMap();
};
myclass.cc:
#include <map>
#include "myclass.h"
myclass::mystruct::mystruct(int j) : i(j) {};
myclass::mystruct::mystruct() : i(-1) {};
bool ::myclass::mystruct::operator==(const ::myclass::mystruct& rhs) {return i==rhs.i; }
bool ::myclass::mystruct::operator>(const ::myclass::mystruct& rhs) {return i>rhs.i; }
bool ::myclass::mystruct::operator<(const ::myclass::mystruct& rhs) {return i<rhs.i; }
::std::map<int,::myclass::mystruct> ::myclass::getStructMap() {
::std::map<int,::myclass::mystruct> structMap;
for (int i=0;i<5;i++) structMap[i]=::myclass::mystruct(i);
return structMap;
}
myprogram.cc:
#include <iostream>
#include <map>
#include "myclass.h"
int main() {
myclass myobj;
::std::map<int,::myclass::mystruct> mymap;
mymap=myobj.getStructMap();
}
compile error:
> g++ -o myprogram myprogram.cc myclass.cc
myclass.cc:12: error: ‘class std::map<int, myclass::mystruct, std::less<int>,std::allocator<std::pair<const int, myclass::mystruct> > >::myclass’ has not been declared
myclass.cc:12: error: ISO C++ forbids declaration of ‘getStructMap’ with no type
myclass.cc: In function ‘int getStructMap()’:
myclass.cc:15: error: cannot convert ‘std::map<int, myclass::mystruct, std::less<int>, std::allocator<std::pair<const int, myclass::mystruct> > >’ to ‘int’ in return
Currently your code in parsed as
/*missing type*/ ::std::map<int,::myclass::mystruct>::myclass::getStructMap()
Thus, first error, map doesn't have myclass member (or subclasses, method, typedef, ...)
then the second error : no return type (so assuming int and thus the conversion error).
So to solve that, in myclass.cc, you may remove extra :: as follow:
::std::map<int,::myclass::mystruct> myclass::getStructMap() {
or add extra parenthesis:
::std::map<int,::myclass::mystruct> (::myclass::getStructMap()) {
In one of my classes, I am trying to use std::priority queue with a specified lambda for comparison:
#pragma once
#include <queue>
#include <vector>
auto compare = [] (const int &a, const int &b) { return a > b; };
class foo
{
public:
foo() { };
~foo() { };
int bar();
private:
std::priority_queue< int, std::vector<int>, decltype(compare)> pq;
};
My program compiles perfectly until I add a .cpp file to accompany the header:
#include "foo.h"
int foo::bar()
{
return 0;
}
This time, my compiler generates an error:
>main.obj : error LNK2005: "class <lambda> compare" (?compare##3V<lambda>##A) already defined in foo.obj
Why can't I create a accompanying .cpp file if my header file contains a lambda?
Compiler: Visual Studio 2012
My main.cpp:
#include "foo.h"
int main(){
return 0;
}
As #Rapptz suggested,
const auto compare = [] (const int &a, const int &b) { return a > b; };
Solved the problem. Why?
Internal vs External linkage. By default, auto, like int has external linkage. So just how:
int j = 5;
In foo.h that would later be included by foo.cpp throws a
Error 2 error LNK2005: "int j" (?j##3HA) already defined in Header.obj
(VS 2013)
However, const makes the linkage internal by default, which means it is only accessible in one translation unit, thereby avoiding the problem.
I'm unable to replicate this problem for some reason. I'm trying this on VS2010 though - not sure if that made a difference. In fact, I tried including your header in two source files and it compiles, links and runs fine.
That said, do you want to consider using std::function. That way you can define the lambda in the cpp code and it won't get defined multiple times for whatever reason. (BTW, where's foo.obj coming from? Do you have another source file that is including this header ?).
foo.h:
#pragma once
#include <queue>
#include <vector>
#include <functional>
typedef std::function<bool (int, int) > comptype;
//auto compare = [] (const int &a, const int &b) { return a > b; };
class foo
{
public:
foo() { };
~foo() { };
int bar();
private:
std::priority_queue< int, std::vector<int>, comptype> pq;
};
Then later in the cpp include and define the lambda and when you create the pq pass it to the constructor.
foo.cpp:
auto compare = [] (const int &a, const int &b) { return a > b; };
foo::foo():pq(compare){}
This way you're deftly not defining the function multiple times.
I am trying to overload the stream operator <<, for a class Foo which has already a toString() function returning a string, with the following code:
std::ostream &operator<<( std::ostream &flux, Foo const& foo )
{
flux << foo.toString();
return flux;
}
In order to use it in a main.cppfile
My question is: Where to put that piece of code?
If I place it in the main.cpp, before its usage, it works well, but i may want to use it in other files.
If I place it in foo.cpp, I get a 'no such function' error:
src/main.cpp:77: error: no match for ‘operator<<’ in ‘std::cout << foo’
which make sense since the code is not included to the main.cpp file
If I place it in the foo.hclass header, outside class declaration, I get a 'multiple definition' error:
foo.o: In function `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Foo const&)':
foo.cpp:(.text+0x0): multiple definition of `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Matrix const&)'
bar.o:bar.cpp:(.text+0x0): first defined here
The foo.h header is indeed included in different classes/files, but there is a ifdef guard, so I don't understand this.
So How should I do?
There are multiple options:
Declare it in the header, after Foo, and define it in Foo.cpp.
//foo.h
class Foo
{};
std::ostream &operator<<( std::ostream &s, Foo const& foo );
//foo.cpp
#include "foo.h"
std::ostream &operator<<( std::ostream &s, Foo const& foo )
{
return s;
}
Define it as a friend inside the class definition.
//Foo.h
class Foo
{
friend std::ostream &operator<<( std::ostream &s, Foo const& foo )
{
return s;
}
};
Define it in the header, outside the class definition, and mark it as inline to prevent the multiple definition.
//Foo.h
class Foo
{
};
inline std::ostream &operator<<( std::ostream &s, Foo const& foo )
{
return s;
}
Put the prototype of the overload by the class declaration, the implementation thereof at the Foo implementation (or if you want it inline, put it at the Foo declaration).
So either:
// foo.h
#ifndef FOO_H_ASDSADKJSLADJL
#define FOO_H_ASDSADKJSLADJL
class Foo {
};
std::ostream& operator<< (std::ostream &, Foo const &);
#endif // FOO_H_ASDSADKJSLADJL
// foo.cpp
#include "foo.h"
....
std::ostream& operator<< (std::ostream &os, Foo const &) {
....
return os;
}
or
#ifndef FOO_H_ASDSADKJSLADJL
#define FOO_H_ASDSADKJSLADJL
class Foo {
};
inline std::ostream& operator<< (std::ostream &os, Foo const &) {
....
return os;
}
#endif // FOO_H_ASDSADKJSLADJL
Your error of the compiler not finding it was the lack of a prototype of your overload.
Put the declaration in the header file, and the definition in the cpp file.
That is, put
std::ostream &operator<<( std::ostream &flux, Foo const& foo );
in your header file, and put
std::ostream &operator<<( std::ostream &flux, Foo const& foo )
{
flux << foo.toString();
return flux;
}
in your cpp file.
This way, you can include the header file wherever you want, and things can use the function, but it will only be defined once, so you won't get the multiple definitions error.
Declare it in the header, where you declare Foo, define it in the source, where you define Foo methods.
As ususal with C and C++, you should
put the actual code into the appropriate .c / .cpp file - here I would recommend foo.cpp
put a predeclaration into the appropriate .h/.hpp header file, with an appropriate #ifdef guard for everything that is used from outside the main c/cpp file.
In some situations, you can use a #define macro, or an inline function. This should then be done in the header; there shouldn't be a multiple declaration error because of the inlining.
Technically you can do a lot of things. I recommend sticking to the best practise of defining the API in the header file, and putting the implementation into the code file. This is most extensible. The inline hack will work for this case, but if you at some later point decides to enhance the method and remove the inline, it will surprisingly break.
The header / code split is least likely to break.