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
Related
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
I am a beginner with threads and am trying to write code to extract 20 tags from a file.
The number of files can run up to 7000, so I would like to make good use of a thread-pool.
I use Code::Blocks 20.3 and MinGW 17.1 on a Windows 10 Pro computer.
I have 'borrowed' the thread-pool code from: https://codereview.stackexchange.com/questions/221626/c17-thread-pool
I made a test that MinGW probably handles as C code, and that worked just fine.
My project involves multiple class files with dialog windows, and when I copied the working C code it fails to build. Unfortunately I do not understand how to convert the code from C to C++.
The test code I wrote is below.
The build messages are:
||=== Build: Debug in ThreadPool2 (compiler: GNU GCC Compiler) ===|
Threadpool.h||In instantiation of 'auto Thread_Pool::execute(F, Args&& ...) [with F = TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>); Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}]':|
TrackTags.cpp|43|required from here|
Threadpool.h|62|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
Threadpool.h|63|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
Threadpool.h|62|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
Threadpool.h|63|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
TrackTags.cpp||In member function 'void TrackTags::GetMultiStdTags()':|
TrackTags.cpp|43|error: invalid use of void expression|
||=== Build failed: 5 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|
the lines with errors are:
TrackTags.cpp
[43] StdFutures.push_back(Pool.execute(GetStdTags, wsFile, wsCol));
Threadpool.h
[62] std::packaged_task<std::invoke_result_t<F, Args...>()> Task_PKG(std::bind(function, args...) );
[63] std::future<std::invoke_result_t<F, Args...>> Future = Task_PKG.get_future();
in Threadpool.h.
I tried:
[43] StdFutures.push_back(Pool.execute(std::mem_fn(TrackTags::GetStdTags), std::ref(wsFile), std::ref(wsCol)));
But this did not help.
I hope someone can help me make this work.
Thank you.
Ruud.
---TrackTags.h---
#ifndef TRACKTAGS_H
#define TRACKTAGS_H
#include "Threadpool.h"
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
#include <vector>
class TrackTags
{
public:
struct TagsStdStrings
{
bool OK;
std::string ThreadID;
std::string FileName;
std::string Collection;
};
public:
TrackTags();
virtual ~TrackTags();
TagsStdStrings GetStdTags(std::string wsFile, std::string wsCollection);
void GetMultiStdTags();
protected:
private:
};
#endif // TRACKTAGS_H
---TrackTags.cpp---
#include "TrackTags.h"
#define _UNICODE
TrackTags::TrackTags()
{
//ctor
}
TrackTags::~TrackTags()
{
//dtor
}
TrackTags::TagsStdStrings TrackTags::GetStdTags(std::string wsFile, std::string wsCollection)
{
TagsStdStrings TagLine;
TagLine.FileName = wsFile;
TagLine.Collection = wsCollection;
TagLine.OK = true;
// Add thread-ID to the structure
auto tid = std::this_thread::get_id();
std::stringstream ssID;
ssID << tid;
std::string sID{ssID.str()};
TagLine.ThreadID = sID;
return TagLine;
}
void TrackTags::GetMultiStdTags()
{
Thread_Pool Pool(1);
std::vector<std::future<TagsStdStrings>> StdFutures;
std::string wsFile{"FileTest"};
std::string wsCol{"ColTest"};
StdFutures.push_back(Pool.execute(GetStdTags, wsFile, wsCol));
for (auto &Fut : StdFutures)
{
TagsStdStrings TSS;
TSS = Fut.get();
if (TSS.OK)
{ std::cout << TSS.ThreadID << "--" << TSS.FileName << "--" << TSS.Collection << std::endl; }
else
{ std::cout << "Empty Tag structure\n"; }
}
}
---Threadpool.h---
#pragma once
#include <condition_variable>
#include <functional> //bind
#include <future> //packaged_task
#include <mutex>
#include <queue>
#include <thread>
#include <type_traits> //invoke_result
#include <vector>
class Thread_Pool
{
public:
Thread_Pool(size_t Thread_Count);
~Thread_Pool();
Thread_Pool(const Thread_Pool &) = delete;
Thread_Pool &operator=(const Thread_Pool &) = delete;
template <typename F, typename ...Args>
auto execute(F, Args&&...);
private:
class Task_Container_Base
{
public:
virtual ~Task_Container_Base() {};
virtual void operator()() = 0;
};
template <typename F>
class Task_Container : public Task_Container_Base
{
public:
Task_Container(F &&Fnc) : f(std::forward<F>(Fnc)) {}
void operator()() override { f(); }
private:
F f;
};
template <typename Func>
static std::unique_ptr<Task_Container_Base> Allocate_Task_Container(Func &&f)
{
return std::unique_ptr<Task_Container_Base>(new Task_Container<Func>(std::forward<Func>(f))
);
}
std::vector<std::thread> Threads;
std::queue<std::unique_ptr<Task_Container_Base>> Tasks;
std::mutex Task_Mutex;
std::condition_variable Task_CV;
bool Stop_Threads = false;
};
template <typename F, typename ...Args>
auto Thread_Pool::execute(F function, Args &&...args)
{
std::unique_lock<std::mutex> Queue_Lock(Task_Mutex, std::defer_lock);
std::packaged_task<std::invoke_result_t<F, Args...>()> Task_PKG(std::bind(function, args...) );
std::future<std::invoke_result_t<F, Args...>> Future = Task_PKG.get_future();
Queue_Lock.lock();
Tasks.emplace(Allocate_Task_Container( [Task(std::move(Task_PKG))]() mutable { Task(); }) );
Queue_Lock.unlock();
Task_CV.notify_one();
return Future;
}
---Threadpool.cpp---
#include "Threadpool.h"
Thread_Pool::Thread_Pool(size_t Thread_Count)
{
for (size_t i = 0; i < Thread_Count; ++i)
{
Threads.emplace_back( std::thread( [&]()
{
std::unique_lock<std::mutex> Queue_Lock(Task_Mutex, std::defer_lock);
while (true)
{
Queue_Lock.lock();
Task_CV.wait( Queue_Lock, [&]() -> bool { return !Tasks.empty() || Stop_Threads; } );
if (Stop_Threads && Tasks.empty()) return;
auto Temp_Task = std::move(Tasks.front());
Tasks.pop();
Queue_Lock.unlock();
(*Temp_Task)();
}
} ) );
}
}
Thread_Pool::~Thread_Pool()
{
Stop_Threads = true;
Task_CV.notify_all();
for (std::thread &Thread : Threads)
{
Thread.join();
}
}
GetStdTags is a non-static member function. You have access to this - the pointer to the object you're calling it on - inside it. Therefore when you call it, you need to specify the object which the member function should be working on.
Pool.execute(GetStdTags, wsFile, wsCol)
Here you only specify the two formal arguments, but not the object for the member function. Passing that along would look like this:
TrackTags one_object; // < yes, ONE, shared between the threads!
// if you don't want to share it between threads,
// you need to create multiple objects (and keep them alive)
Pool.execute(&TrackTags::GetStdTags, &one_object, wsFile, wsCol)
// ^ pointer to member ^ pointer
// function to object,
// "this" inside the
// member function
More information about std::bind and member functions.
However, since your class (TrackTags) doesn't have any data members and the member function GetStdTags doesn't need access to any object of type TrackTags, you can make it a static member function (or even a free function, really) and get by without a TrackTags object.
Thank you Daniel.
The test project seemed to work, so I started on the "real" thing.
It is building without errors, but not working as planned.
I tested with 4 threads and 4 files and ran it twice.
Result below: What did I miss?
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\01 Adam Baldych - Bridges.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\02 Adam Baldych - Polesie.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\03 Adam Baldych - Mosaic.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\04 Adam Baldych - Riese.flac
6--Riese--Col Test
7--Riese--Col Test
8--Riese--Col Test
9--Riese--Col Test
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\01 Adam Baldych - Bridges.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\02 Adam Baldych - Polesie.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\03 Adam Baldych - Mosaic.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\04 Adam Baldych - Riese.flac
First run, completes, but with wrong results, and the second run immediately after the first completed hangs.
This is the function called:
TrackTags::TagsStruct TrackTags::GetTags(wxString wsFile, wxString wsCollection)
{
// create Tag variable structure
struct TagsStruct TagLine;
.
.
return TagLine
}
It loads a DLL and extracts the required tags from a file to return it in a structure with the Thread-ID as first item (temporary to check how the code runs).
The calling function is below:
void TrackTags::GetMultiStdTags()
{
wxString wsCol{"Col Test"};
std::vector<wxString> wsTracks
{
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\01 Adam Baldych - Bridges.flac",
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\02 Adam Baldych - Polesie.flac",
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\03 Adam Baldych - Mosaic.flac",
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\04 Adam Baldych - Riese.flac"
};
TrackTags one_object;
Thread_Pool Pool(4);
std::vector<std::future<TagsStruct>> StdFutures;
for (auto &tr : wsTracks)
{
std::cout << tr << std::endl;
StdFutures.push_back(Pool.execute(&TrackTags::GetTags, &one_object, tr, wsCol));
}
for (auto &Fut : StdFutures)
{
TagsStruct TSS;
TSS = Fut.get();
if (TSS.OK)
{ std::cout << TSS.ThreadID << "--" << TSS.TrackTitle << "--" << TSS.Collection << std::endl; }
else
{ std::cout << "Empty Tag structure found\n"; }
}
}
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 5 years ago.
I've applied all the solutions provided by you for similar problems but I'm still getting this error:
undefined reference to `setgolf(golf&, char*, int)'
collect2: error: ld returned 1 exit status
here is the code header
#ifndef SANS_H_INCLUDED
#define SANS_H_INCLUDED
const int len = 40;
struct golf
{
char fullname[len];
int handicap;
};
//void setgolf(golf &,char * ,int);
int setgolf(golf &);
void sethandicap(golf &,int );
void showgolf(const golf &);
#endif
here is the file containing the functions definitions
#include <iostream>
#include <cstring>
#include "chapter9exe3.h"
void setgolf(golf & s,char *c ,int hc)
{
strcpy(s.fullname,c);
s.handicap=hc;
}
int setgolf(golf & s)
{
std::cin.getline(s.fullname,len);
if(s.fullname[0] == '\0'&& s.fullname[1] == '\0' && s.fullname[2] == '\0')
return 0;
else
return 1;
}
void sethandicap(golf & s,int n )
{
s.handicap = n;
}
void showgolf(const golf & s)
{
std::cout<<"the full name :"<<s.fullname<<std::endl;
std::cout<<"the handcape :"<<s.handicap<<std::endl;
}
here is the file containing the main function
#include <iostream>
#include "sans.h"
int main()
{
golf player;
char name[len] = "santers God's men";
int handicap = 84;
setgolf(player,name,handicap);
return 0;
}
Uncomment this:
//void setgolf(golf &,char * ,int);
in your header file, since you are doing in main:
setgolf(player,name,handicap);
which will search for a matching prototype in the header file, and will fail to fidn it, because you have commented it.
In other words, you call the function with three parameters, but only provide a prototype of this function in the header file with one parameter. As a result, the reference to setgolf() with three parameters is definetely undefined!
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.
I think they are called functors? (it's been a while)
Basically, I want to store a pointer to a function in a variable, so I can specify what function I want to use from the command line.
all the functions return and take the same values.
unsigned int func_1 (unsigned int var1)
unsigned int func_2 (unsigned int var1)
function_pointer = either of the above?
so then I could call it by going: function_pointer(my_variable)?
EDIT:
as per #larsmans's suggestion, I've gotten this:
Config.h:
class Config
{
public:
unsigned static int (*current_hash_function)(unsigned int);
};
Config.cpp:
#include "Config.h"
#include "hashes.h"
unsigned static int (*current_hash_function)(unsigned int) = kennys_hash_16;
hashes.h:
unsigned int kennys_hash(unsigned int out);
unsigned int kennys_hash_16(unsigned int out);
hashes.cpp:
just implements the functions in the header
main.cpp:
#include "Config.h"
#include "hashes.h"
// in test_network:
unsigned int hashed = Config::current_hash_function(output_binary);
//in main():
else if (strcmp(argv[i], "-kennys_hash_16") == 0)
{
Config::current_hash_function = kennys_hash_16;
}
else if (strcmp(argv[i], "-kennys_hash_8") == 0)
{
Config::current_hash_function = kennys_hash;
}
the error I get:
g++ -o hPif src/main.o src/fann_utils.o src/hashes.o src/Config.o -lfann -L/usr/local/lib
Undefined symbols:
"Config::current_hash_function", referenced from:
test_network() in main.o // the place in the code I've selected to show
auto_test_network_with_random_data(unsigned int, unsigned int, unsigned int)in main.o
generate_data(unsigned int, unsigned int, unsigned int)in main.o
_main in main.o // the place in the code I've selected to show
_main in main.o // the place in the code I've selected to show
generate_train_file() in fann_utils.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [hPif] Error 1
The simplest you can do is
unsigned int (*pFunc)(unsigned int) = func_1;
This is a bare function pointer, which cannot be used to point to anything other than a free function.
You can make it less painful if your compiler supports the C++0x auto keyword:
auto pFunc = func_1;
In any case, you can call the function with
unsigned int result = pFunc(100);
There are many other options that provide generality, for example:
You can use boost::function with any C++ compiler
With a compiler implementing features of C++0x you can use std::function
These can be used to point to any entity that can be invoked with the appropriate signature (it's actually objects that implement an operator() that are called functors).
Update (to address updated question)
Your immediate problem is that you attempt to use Config::current_hash_function (which you declare just fine) but fail to define it.
This defines a global static pointer to a function, unrelated to anything in class Config:
unsigned static int (*current_hash_function)(unsigned int) = kennys_hash_16;
This is what you need instead:
unsigned int (*Config::current_hash_function)(unsigned int) = kennys_hash_16;
From C++11 you can use std::function to store functions. To store function you use it as follsonig:
std::function<return type(parameter type(s))>
as an example here it is:
#include <functional>
#include <iostream>
int fact (int a) {
return a > 1 ? fact (a - 1) * n : 1;
}
int pow (int b, int p) {
return p > 1 ? pow (b, p - 1) * b : b;
}
int main (void) {
std::function<int(int)> factorial = fact;
std::function<int(int, int)> power = pow;
// usage
factorial (5);
power (2, 5);
}
No, these are called function pointers.
unsigned int (*fp)(unsigned int) = func_1;
You could also use function either from the c++0x or from boost.
That would be
boost::function<int(int)>
and then use bind to bind your function to this type.
Have a look here and here
Ok here would be a example. I hope that helps.
int MyFunc1(int i)
{
std::cout << "MyFunc1: " << i << std::endl;
return i;
}
int MyFunc2(int i)
{
std::cout << "MyFunc2: " << i << std::endl;
return i;
}
int main(int /*argc*/, char** /*argv*/)
{
typedef boost::function<int(int)> Function_t;
Function_t myFunc1 = boost::bind(&MyFunc1, _1);
Function_t myFunc2 = boost::bind(&MyFunc2, _1);
myFunc1(5);
myFunc2(6);
}
You can store a function in a variable in c++ in this way
auto function_name = [&](params){
statements
};
auto add = [&](int a,int b){
return a+b;
};
cout<<add(5,6);
typedef unsigned int (*PGNSI)(unsigned int);
PGNSI variable1 = func_1;
PGNSI variable2 = func_2;
unsigned int (* myFuncPointer)(unsigned int) = &func_1;
However, the syntax for function pointers is awful, so it's common to typedef them:
typedef unsigned int (* myFuncPointerType)(unsigned int);
myFuncPointerType fp = &func_1;
IF you have Boost installed, you can also check out Boost Function.