I am trying to call the following function template:
template<typename T>
bool select(const std::string& ddbbName,
const std::string& sql,
std::vector<std::shared_ptr<T>>& vResultSet,
SqlErrorInfo& errorInfo);
which is defined in a class whose name is SQLite3Manager. In the following code this "select" method does nothing (a part from returning "true"). I have tried to simplify the problem description, because the problem seems to be related to the way I am calling/using/defining that method.
So the main.cpp code is:
main.cpp
#include <iostream>
#include "ES.h"
#include "SQLiteMgr.h"
int main(int argc, const char * argv[])
{
// To get an instance of the singleton
Cucut::SQLite3Manager& _sqliteMgr = Cucut::SQLite3Manager::getInstance();
std::string ddbbName("Cucut.db");
std::string sql("SELECT * FROM ES");
std::vector<std::shared_ptr<Cucut::ES>> vspEs;
Cucut::SqlErrorInfo sqlErrorInfo;
// Call the template method for <Cucut::ES> using the instance of the singleton
bool result = _sqliteMgr.select<Cucut::ES>(ddbbName, sql, vspEs, sqlErrorInfo);
return result;
}
but I get the following link error in Xcode 5:
Undefined symbols for architecture x86_64:
"bool Cucut::SQLite3Manager::select<Cucut::ES>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::shared_ptr<Cucut::ES>, std::__1::allocator<std::__1::shared_ptr<Cucut::ES> > >&, Cucut::SqlErrorInfo&)", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The full code is:
ES.h file:
#ifndef __TestSharedPtr__ES__
#define __TestSharedPtr__ES__
#include <iostream>
namespace Cucut
{
class ES
{
public:
ES();
const unsigned int& getId() const;
void setId(const unsigned int& id);
private:
unsigned int _id;
};
}
#endif /* defined(__TestSharedPtr__ES__) */
ES.cpp file:
#include "ES.h"
namespace Cucut
{
ES::ES() :
_id(0)
{
}
const unsigned int& ES::getId() const
{
return _id;
}
void ES::setId(const unsigned int& id)
{
_id = id;
}
}
SQLiteMgr.h file:
#ifndef __TestSharedPtr__SQLiteMgr__
#define __TestSharedPtr__SQLiteMgr__
#include <iostream>
#include <vector>
#include <memory>
namespace Cucut
{
struct SqlErrorInfo
{
int rc;
std::string description;
};
class SQLite3Manager
{
private:
SQLite3Manager();
SQLite3Manager(const SQLite3Manager& rs);
SQLite3Manager(SQLite3Manager&& rs);
SQLite3Manager& operator = (const SQLite3Manager& rs);
SQLite3Manager& operator = (SQLite3Manager&& rs);
public:
static SQLite3Manager& getInstance();
template<typename T>
bool select(const std::string& ddbbName,
const std::string& sql,
std::vector<std::shared_ptr<T>>& vResultSet,
SqlErrorInfo& errorInfo);
};
}
#endif /* defined(__TestSharedPtr__SQLiteMgr__) */
And finally the SQLiteMgr.cpp file:
#include <memory>
#include <vector>
#include "SQLiteMgr.h"
namespace Cucut
{
SQLite3Manager::SQLite3Manager()
{
}
SQLite3Manager& SQLite3Manager::getInstance()
{
static SQLite3Manager instance;
return instance;
}
template<typename T>
bool SQLite3Manager::select(const std::string& ddbbName,
const std::string& sql,
std::vector<std::shared_ptr<T>>& vResultSet,
SqlErrorInfo& errorInfo)
{
return true;
}
}
Do not be distract with the name "SqliteMgr" because in the aforementioned example I have removed any kind of reference to sqlite3 in order to simplify the problem; so, it seems that I am not calling or defining the method "select" in the correct way because I get the aforementioned link error.
Any help will be appreciated. Thanks in advance.
Function template definitions must always be in the header file so that code can be generated at the point of instantiation (here in main). If you don't do this, the compiler will expect you to manually instantiate the template, which is why there is a linker error. Move the body of the select function to SQLiteMgr.h and it will work.
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.
This question already has answers here:
c++: class declaration and definition separated inside header causes Duplicate Symbol
(2 answers)
Closed 1 year ago.
I created a struct:
{
unsigned int id;
std::string name;
unsigned int maxPlayers;
unsigned int numOfQuestionsInGame;
unsigned int timePerQuestion;
unsigned int isActive;
} RoomData;
In my code, I have to create a vector of RoomData and then convert it into a json object (I'm using nlohmann, and unable to use any other method due to restrictions in my instructions), and to do so, i tried to create a from_json and to_json functions.
The code itself (this is the header file of the code):
#include <iostream>
#include <string>
#include <vector>
#include "LoggedUser.h"
#include "json.hpp"
namespace nh = nlohmann;
namespace rd {
typedef struct RoomData
{
unsigned int id;
std::string name;
unsigned int maxPlayers;
unsigned int numOfQuestionsInGame;
unsigned int timePerQuestion;
unsigned int isActive;
} RoomData;
void from_json(const nh::json& j, RoomData& val)
{
j.at("id").get_to(val.id);
j.at("name").get_to(val.name);
j.at("maxPlayers").get_to(val.maxPlayers);
j.at("numOfQuestionsInGame").get_to(val.numOfQuestionsInGame);
j.at("timePerQuestion").get_to(val.timePerQuestion);
j.at("isActive").get_to(val.isActive);
}
void to_json(nh::json& j, const RoomData& val)
{
j["id"] = val.id;
j["name"] = val.name;
j["maxPlayers"] = val.maxPlayers;
j["numOfQuestionsInGame"] = val.numOfQuestionsInGame;
j["timePerQuestion"] = val.timePerQuestion;
j["isActive"] = val.isActive;
}
}
class Room
{
public:
Room() = default;
Room(const rd::RoomData& data);
void addUser(LoggedUser); // adds a user to the users vector
void removeUser(LoggedUser); // removes a user from the users vector
std::vector<std::string> getAllUsers(); // return a vector of all the users
// getters
rd::RoomData getRoomData() const;
private:
rd::RoomData m_metadata; // the data of the room
std::vector<LoggedUser> m_users; // the vector of the users in the room
};
After trying to run it, a LNK2005 error arises. I know that the type I use and those functions have to be in the same namespace, did I do it wrong?
The exact error:
"void cdecl to_json(class nlohmann::basic_json<class std::map,class std::vector,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,bool,int64,unsigned __int64,double,class std::allocator,struct nlohmann::adl_serializer,class std::vector<unsigned char,class std::allocator<unsigned char> > > &,struct RoomData const &)" (?to_json##YAXAAV?$basic_json#Vmap#std##Vvector#2#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##2#_N_J_KNVallocator#2#Uadl_serializer#nlohmann##V?$vector#EV?$allocator#E#std###2##nlohmann##ABURoomData###Z) already defined in Communicator.obj
Apparently, to solve this kind of issue, all I had to do was adding "inline" at the start of the function.
Example:
inline void to_json(nh::json& j, const RoomData& val)
My reference: https://github.com/nlohmann/json/issues/542
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 2 years ago.
I created a library in C++ called libparse, the code is used by another library named libitcmpmsg.so.
I've been trying to test libitcmpmsg in test.cpp, however when I try to build it the compiler returns the following messages:
$libpath/libitcmpmsg.so: reference not found to "void MSG_PARSER::WriteBigEndian<unsigned char>(std::vector<unsigned char, std::allocator<unsigned char> &, unsingned char)"
$libpath/libitcmpmsg.so: reference not found to "unsigned char* MSG_PARSER::ReadBigEndian<unsigned char>(unsigned char&, unsigned char*, unsigned int&)"
$libpath/libitcmpmsg.so: reference not found to "MSG_PARSER::ReadFixedLengthString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned char*, int, unsigned int&)"
$libpath/libitcmpmsg.so: reference not found to "MSG_PARSER::WriteFixedLengthString(std::vector<unsigned char, std::allocator<unsigned char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)"
libpath just represents the path to the library. MSG_PARSER is the namespace from libparser.
The functions' scopes, from the error messages, in msg_parser.h are:
template <class T>
void WriteBigEndian(std::vector<uint8_t>& target, T source);
template <class T>
uint8_t* ReadBigEndian(T &target, uint8_t* source, uint32_t &available);
uint8_t* ReadFixedLengthString(string& target, uint8_t *source, int size, uint32_t &available);
void WriteFixedLengthString(std::vector<uint8_t> &target, const string& source, uint32_t size);
It seems that libitcmpmsg is passing the wrong type of arguments to libparser.so.
Below, it is a code snippet where libparer.so is being used by libitcmpmsg.so
#include "ptcinteraction.h"
#include "msg_parser.h"
#include <stdint.h>
using namespace PTC_INTERACTION;
using namespace MSG_PARSER;
PtcInteraction::PtcInteraction( std::vector<uint8_t> &data )
{
m_msgBuffer.clear();
uint32_t tavailable = static_cast<uint32_t>(data.size());
uint8_t *tsource = &data[0];
uint8_t value = 0;
tsource = ReadFixedLengthString(m_message.railScac, tsource, SCAC_SIZE, tavailable);
tsource = ReadBigEndian<uint8_t>(m_message.sizeOfPromptTxt, tsource, tavailable );
tsource = ReadFixedLengthString(m_message.promptTxt, tsource, m_message.sizeOfPromptTxt, tavailable);
tsource = ReadBigEndian<uint8_t>(m_message.sizeOfKeyPressedTxt, tsource, tavailable );
tsource = ReadFixedLengthString(m_message.keyPressedTxt, tsource, m_message.sizeOfKeyPressedTxt, tavailable);
if((&data[0] + data.size()) == tsource)
{
m_msgBuffer = data;
}
else
{
m_msgBuffer = {};
}
}
PtcInteraction::PtcInteraction( OCCPTCMSG::PtcInteractionT &ptcInteraction)
{
m_msgBuffer.clear();
m_message = ptcInteraction;
WriteFixedLengthString(m_msgBuffer, ptcInteraction.railScac, SCAC_SIZE);
WriteBigEndian<uint8_t>(m_msgBuffer, ptcInteraction.sizeOfPromptTxt );
.
.
.
PTCInteraction is a class from libitcmpmsg.so, while PtcInteractionT is a strucuture also defined by libitcmpmsg.
The test code is represented below:
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include "ptcinteraction.h"
#include "occptcmessages_generated.h"
#include "msg_parser.h"
#include <cstdio>
using namespace PTC_INTERACTION;
int main(void)
{
OCCPTCMSG::PtcInteractionT teste;
teste.railScac = "abcd";
teste.promptTxt = "message test";
teste.sizeOfPromptTxt = teste.promptTxt.size();
teste.keyPressedTxt = "test";
teste.sizeOfKeyPressedTxt = teste.keyPressedTxt.size();
PTC_INTERACTION::PtcInteraction ptcInter(teste);
PTC_INTERACTION::PtcInteraction ptcInter2(ptcInter.m_msgBuffer);
if ( (ptcInter.m_message.railScac == ptcInter2.m_message.railScac) &&
(ptcInter.m_message.promptTxt == ptcInter2.m_message.promptTxt) &&
(ptcInter.m_message.sizeOfPromptTxt == ptcInter2.m_message.sizeOfPromptTxt) &&
(ptcInter.m_message.keyPressedTxt == ptcInter2.m_message.keyPressedTxt) &&
(ptcInter.m_message.sizeOfKeyPressedTxt == ptcInter2.m_message.sizeOfKeyPressedTxt) )
{
std::cout << "Serialization and deserialization succeeded" << std::endl;
}
}
There are 3 CMakeLists employed in the code development:
libparser builder;
libitcmpmsg builder;
test builder.
Does anyone know why compiler returns the 4 error messages described in the beginning of the question?
How can I solve the problems?
Let me know if you need CMakeLists code to better understand the problem.
You have to instantiate the specialized template classes in the cpp, or either put the body of template classes in the header: https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl
I want to have a singleton in my project but some errors occur
this is my codes in three separate files.:
//---------------My main.cpp code
#include <iostream>
#include "Sports/BBVB.h"
int main() {
bbvb;
return 0;
}
// ---------------------------my BBVB.h code
#ifndef SAMAVAR_BBVB_H
#define SAMAVAR_BBVB_H
typedef struct VBResult{
int set1=-1;
int set2=-1;
int set3=-1;
int set4=-1;
int set5=-1;
}VBResult;
#include "Sport.h"
#include "../TournamentStuf/Tournament.h"
class BBVB: public Sport {
protected:
vector<Tournament<VBResult>> tours;
public:
static BBVB& getInstance(){
static BBVB b;
return b;
}
private:
BBVB(){}
public:
BBVB(BBVB const&)=delete;
void operator=(BBVB const&) = delete;
//-------------Setter------------
//------------Getter-------------
vector<Tournament<VBResult>> getTours() const;
Tournament<VBResult> getTourById(int id) const;
//----------Others---------------
void addTour(Tournament<VBResult> v);
};
BBVB &bbvb=BBVB::getInstance();
#endif //SAMAVAR_BBVB_H
//------------------my Store and restore code
#ifndef SAMAVAR_STOREANDRESTORE_H
#define SAMAVAR_STOREANDRESTORE_H
#include "../Sports/BBVB.h"
#include "../Sports/PingPong.h"
#include "../Sports/Wrestling.h"
void Start(BBVB &b);
void Update(const BBVB &b);
void Start(PingPong &p);
void Update(const PingPong &p);
void Start(Wrestling &w);
void Update(const Wrestling &w);
#endif //SAMAVAR_STOREANDRESTORE_H
I have a bbvb instance of BBVB but it says you have multiple definitions of it.
I'm new to Clion and I don't have enough information about somethings like cmake and I feel the problem is because of it.
I want to have something like cout and cin in iostream.so by including my BBVB I can access this object.
Clion shows error below:
CMakeFiles\Samavar.dir/objects.a(BBVB.cpp.obj):BBVB.cpp:(.bss+0x0): multiple definition of `bbvb'
CMakeFiles\Samavar.dir/objects.a(main.cpp.obj):main.cpp:(.bss+0x0): first defined here
CMakeFiles\Samavar.dir/objects.a(StoreAndRestore.cpp.obj):StoreAndRestore.cpp:(.bss+0x0): multiple definition of `bbvb'
CMakeFiles\Samavar.dir/objects.a(main.cpp.obj):Samavar-master/Sports/BBVB.h:24: first defined here
collect2.exe: error: ld returned 1 exit status
I am writing a simple server program using ICE by ZeroC. When I try to link the .o files it gave me the following error message:
$ c++ -o server UserMap.o Server.o -L/Library/Developer/Ice-3.5.0/lib -lIce -lIceUtil
Undefined symbols for architecture x86_64:
"VTT for UserMapI", referenced from:
UserMapI::UserMapI() in Server.o
"vtable for UserMapI", referenced from:
UserMapI::UserMapI() in Server.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
After some googling I understand that the problem is I have an abstract class with 3 virtual methods declared in UserMap.ice (and hence in UserMap.h and UserMap.cpp generated by the command slice2cpp UserMap.ice), and in Server.cpp I have a class called UserMapI:public UserMap which implements the three virtual methods and another private helper function. The error is generated because the compiler thinks I have declared all functions(methods) in UserMap.h and UserMap.cpp.
My understanding to this problem is that I should modify the link command so that the linker will know that there are more functions in UserMapI declared in Server.cpp, but I don't have enough knowledge to do the modification. Can someone help me please?
Thank you all.
Here is the compiler command I am using to get Server.o and UserMap.o:
c++ -I. -I/Library/Developer/Ice-3.5.0/include -c UserMap.cpp Server.cpp
Here's the code of UserMap.ice:
module DR
{
class UserMap
{
void addUserToLocation(int userID, int x, int y);
string getUsersNearLocation(int x, int y, int distance);
void removeFromMap(int userID, int x, int y);
};
};
slice2cpp command slices this .ice file into a .h and a .cpp file that works as an API between server and client.
In Server.cpp I have the following include:
#include <Ice/Ice.h>
#include "UserMap.h"
#include <map>
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
and the following subclass:
class UserMapI : public UserMap
{
public:
virtual void addUserToLocation(int userID, int x, int y, const Ice::Current &);
virtual string getUsersNearLocation(int x, int y, int distance, const Ice::Current &);
virtual void removeFromMap(int userID, int x, int y, const Ice::Current &);
private:
string stringify(int x, int y);
};
And after implementing all methods here's the main function:
int main(int argc, char* argv[])
{
int status = 0;
Ice::CommunicatorPtr ic;
try {
ic = Ice::initialize(argc, argv);
Ice::ObjectAdapterPtr adapter = ic->createObjectAdapterWithEndpoints("SimpleUserMapAdapter", "default -p 10000");
Ice::ObjectPtr object = new UserMapI;
adapter->add(object, ic->stringToIdentity("SimpleUserMap"));
adapter->activate();
ic->waitForShutdown();
} catch (const Ice::Exception & e) {
cerr << e << endl;
status = 1;
} catch (const char * msg) {
cerr << msg << endl;
status = 1;
}
if (ic){
try {
ic->destroy();
} catch (const Ice::Exception & e) {
cerr << e << endl;
status = 1;
}
}
return status;
}
Here's the UserMap.h.