Passing template argument to template function in a thread - c++

I'm new to templates, so I decided to write out unit tests for some concurrent code I am writing, but I can't seem to get them to compile. The specific error is:
error C2664: 'std::thread::thread(const std::thread &)' : cannot convert argument 1 from 'void (__cdecl *)(lock &)' to 'void (__cdecl &)(Utility_UnitTests::emptyLock &)'
1> None of the functions with this name in scope match the target type
1> w:\code dumpster\utility_unittests\utspinlock.cpp(88) : see reference to function template instantiation 'void Utility_UnitTests::UTSpinLock::lockContension<Utility_UnitTests::emptyLock>(lock &)' being compiled
1> with
1> [
1> lock=Utility_UnitTests::emptyLock
1> ]
The issue is pretty clear from the compiler, I am not passing the correct type, but I have no clue how to fix it! Thanks in advance!
EDIT: I forgot to mention, I am using Visual Studio 2013
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace Utility_UnitTests
{
typedef utils::threading::SpinLock<utils::threading::backoff::empty> emptyLock;
typedef utils::threading::SpinLock<utils::threading::backoff::yield> yieldingLock;
typedef utils::threading::SpinLock<utils::threading::backoff::pause> pausingLock;
TEST_CLASS(UTSpinLock)
{
public:
template<typename lock>
void lockAndSleepT(lock &l)
{
l.lock();
std::this_thread::sleep_for(std::chrono::nanoseconds(10));
l.unlock();
}
template<typename lock>
void lockContension(lock &l)
{
std::thread t1(&UTSpinLock::lockAndSleepT<lock>, this, std::ref(l));
Assert::AreEqual(true, l.isLocked());
t1.join();
Assert::AreEqual(false, l.isLocked());
}
TEST_METHOD(testLockContension)
{
UTSpinLock::lockContension(m_emptySpin);
UTSpinLock::lockContension(m_yieldingSpin);
UTSpinLock::lockContension(m_pausingSpin);
}
private:
emptyLock m_emptySpin;
yieldingLock m_yieldingSpin;
pausingLock m_pausingSpin;
};
}

First of all, this is certainly a bug in the MSVC implementation. It seems to be having trouble when the first argument to std::thread is a pointer to a member function template. On my machine, the 64-bit compiler produces the same error message, while the 32-bit compiler crashes. Thankfully, you can work around this in quite a few ways, all involving not directly pass a pointer to a member function template to thread.
Option 1 - as you've discovered, creating a bind expression and passing that to thread works.
Option 2 - rewrite the class so that it is a template, and the member functions are not.
template<typename lock>
struct UTSpinLock
{
public:
void lockAndSleepT(lock &l)
{}
void lockContension(lock &l)
{
std::thread t1(&UTSpinLock::lockAndSleepT, this, std::ref(l));
t1.join();
}
};
Option 3 - leave the class definition unchanged, and wrap the pointer to member function template in std::mem_fn
std::thread t1(std::mem_fn(&UTSpinLock::lockAndSleepT<lock>), this, std::ref(l));
Option 4 - no change to the class definition again, this time pass a lambda expression to thread
std::thread t1([&, this](){ lockAndSleepT(l); });

Special thank to WhozCraig! I would accept his answer, but, for some reason, I can't. For those that are interested, I changed:
template<typename lock>
void lockContension(lock &l)
{
std::thread t1(&UTSpinLock::lockAndSleepT<lock>, this, std::ref(l));
Assert::AreEqual(true, l.isLocked());
t1.join();
Assert::AreEqual(false, l.isLocked());
}
To:
template<typename lock>
void lockContension(lock &l)
{
auto bounded = std::bind(&UTSpinLock::lockAndSleepT<lock>, this, std::placeholders::_1);
std::thread t1(bounded, std::ref(l));
Assert::AreEqual(true, l.isLocked());
t1.join();
Assert::AreEqual(false, l.isLocked());
}

Related

std::bind causes "failed to specialize function template" error on MSVC

As a bit of context on the issue I have, I am trying to compile my project using MSVC (Visual Studio 2022) on Windows and it produces a bunch of errors, which is surprising, considering the same code builds just fine on GNU-G++.
What I am trying to do is to write a packet spoofer using the libtins library. I am working on a multi-threaded approach, where one thread captures the packets and pushes them to a queue and the other pops out one packet at a time, does "the spoofing", and then forwards it somewhere else.
A construct is provided for capturing network packets in a loop, in the form of a template function.
/* Credits: M.Fontanini, libtins */
template <typename Functor>
void Tins::BaseSniffer::sniff_loop(Functor function, uint32_t max_packets) {
for(iterator it = begin(); it != end(); ++it) {
try {
// If the functor returns false, we're done
#if TINS_IS_CXX11 && !defined(_MSC_VER)
if (!Tins::Internals::invoke_loop_cb(function, *it)) {
return;
}
#else
if (!function(*it->pdu())) {
return;
}
#endif
}
catch(malformed_packet&) { }
catch(pdu_not_found&) { }
if (max_packets && --max_packets == 0) {
return;
}
}
}
This works by binding a callback function which will be called every time a packet is captured. I have tried to leverage this by creating a wrapper class, called PacketSniffer, where I bind a callback function to Sniffer::sniff_loop which pushes every captured packet to a queue.
bool
PacketSniffer::callback(Tins::Packet &packet,
ThreadSafeQueue<Tins::Packet> &packetq,
bool &running) {
packetq.push(packet);
return running;
}
void PacketSniffer::run(ThreadSafeQueue<Tins::Packet> &packetq, bool &running) {
try {
sniffer_->sniff_loop(std::bind(&PacketSniffer::callback, this,
std::placeholders::_1, std::ref(packetq),
std::ref(running)));
} catch (std::exception &ex) {
throw std::runtime_error(ex.what());
}
}
The actual call where I use this in my app:
// Packet capture
bool running = true;
std::thread capture([&pq = packetq_, st, &running,
&iface_value, &pcap_filter_value]() {
PacketSniffer ps(st, iface_value.data(),
pcap_filter_value.data());
ps.run(pq, running);
});
MSVC compiler error:
C:\Users\adrian\repos\src\spoofer\build\_deps\libtins-src\include\tins/sniffer.h(681,18): error C2672: 'operator __surrogate_func': no matchi
ng overloaded function found [C:\Users\adrian\repos\src\spoofer\build\src\spoofer.vcxproj]
C:\Users\adrian\repos\src\spoofer\src\sniffer.cpp(74): message : see reference to function template instantiation 'void Tins::BaseSniffer::sn
iff_loop<std::_Binder<std::_Unforced,bool (__cdecl spoofer::PacketSniffer::* )(Tins::Packet &,ThreadSafeQueue<Tins::Packet> &,bool &),spoofer::
PacketSniffer *,const std::_Ph<1> &,std::reference_wrapper<ThreadSafeQueue<Tins::Packet>>,std::reference_wrapper<bool>>>(Functor,uint32_t)' b
eing compiled [C:\Users\adrian\repos\src\spoofer\build\src\spoofer.vcxproj]
with
[
Functor=std::_Binder<std::_Unforced,bool (__cdecl spoofer::PacketSniffer::* )(Tins::Packet &,ThreadSafeQueue<Tins::Packet> &,boo
l &),spoofer::PacketSniffer *,const std::_Ph<1> &,std::reference_wrapper<ThreadSafeQueue<Tins::Packet>>,std::reference_wrapper<bool>>
]
C:\Users\adrian\repos\src\spoofer\build\_deps\libtins-src\include\tins/sniffer.h(681,1): error C2893: Failed to specialize function template
'unknown-type std::_Binder<std::_Unforced,bool (__cdecl spoofer::PacketSniffer::* )(Tins::Packet &,ThreadSafeQueue<Tins::Packet> &,bool &),spo
ofy::PacketSniffer *,const std::_Ph<1> &,std::reference_wrapper<ThreadSafeQueue<Tins::Packet>>,std::reference_wrapper<bool>>::operator ()(_Un
bound &&...) noexcept(<expr>) const' [C:\Users\adrian\repos\src\spoofer\build\src\spoofer.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.32.31326\include\functional(2002): message : see declaration of 'std
::_Binder<std::_Unforced,bool (__cdecl spoofer::PacketSniffer::* )(Tins::Packet &,ThreadSafeQueue<Tins::Packet> &,bool &),spoofer::PacketSniffe
r *,const std::_Ph<1> &,std::reference_wrapper<ThreadSafeQueue<Tins::Packet>>,std::reference_wrapper<bool>>::operator ()' [C:\Users\adrian\r
epos\src\spoofer\build\src\spoofer.vcxproj]
C:\Users\adrian\repos\src\spoofer\build\_deps\libtins-src\include\tins/sniffer.h(681,1): message : With the following template arguments: [C:
\Users\adrian\repos\src\spoofer\build\src\spoofer.vcxproj]
C:\Users\adrian\repos\src\spoofer\build\_deps\libtins-src\include\tins/sniffer.h(681,1): message : '_Unbound={Tins::PDU &}' [C:\Users\adrian
\repos\src\spoofer\build\src\spoofer.vcxproj]
A minimal, single threaded example from one of my tests, producing the same error. Don't know how useful this is, as it needs to be compiled and linked against libtins, but maybe it can provide some additional context:
#include <memory>
#include <iostream>
#include <exception>
#include <functional>
#include <tins/tins.h>
#include "utils/queue.h"
enum class SnifferType { Sniffer, FileSniffer };
class PacketSniffer {
public:
PacketSniffer(SnifferType st, const char *iface, const char *capture_filter) {
setup(st, iface, capture_filter);
}
PacketSniffer() = delete;
void run(ThreadSafeQueue<Tins::Packet>& packetq, bool &running);
private:
void setup(SnifferType st, const char *iface, const char *capture_filter) {
Tins::SnifferConfiguration config;
config.set_promisc_mode(true);
config.set_filter(capture_filter);
try {
if (st == SnifferType::FileSniffer) {
sniffer_ = std::make_unique<Tins::FileSniffer>(iface, config);
} else {
sniffer_ = std::make_unique<Tins::Sniffer>(iface, config);
}
} catch (Tins::pcap_error &e) {
throw std::runtime_error(e.what());
} catch (std::exception &e) {
throw std::runtime_error(e.what());
}
}
bool callback(Tins::Packet& packet,
ThreadSafeQueue<Tins::Packet>& packetq,
bool &running){
packetq.push(packet);
return running;
}
std::unique_ptr<Tins::BaseSniffer> sniffer_;
};
struct TestContext {
TestContext(const char *file_path, const char *filter) :
sniffer_({ SnifferType::FileSniffer, file_path, filter}) {}
PacketSniffer sniffer_;
ThreadSafeQueue<Tins::Packet> queue_;
};
int main() {
TestContext ctx("packets.pcap", "");
bool running = true;
ctx.sniffer_.run(ctx.queue_, running);
return 0;
}
What am I missing here regarding std::bind, that produces these errors? I find it weird that the code compiles on G++ but not on MSVC and I think it's related to this somehow.

C++ pass function pointer with parameter to function

I think I have misunderstood how function pointers work. In this example:
class Helper
{
public:
typedef void (*SIMPLECALLBK)(const char*);
Helper(){};
void NotifyHelperbk(SIMPLECALLBK pCbk)
{ m_pSimpleCbk = pSbk; }
private:
SIMPLECALLBK m_pSimpleCbk;
}
// where i call the func
class Main
{
public:
Main(){};
private:
Helper helper
void SessionHelper(const char* msg);
}
Main.cpp
void Main::SessionHelper(const char* msg)
{
....
}
helper.NotifyHelperbk(&Main::SessionHelper);
I get the following error:
error C2664: 'Main::NotifyHelperbk' : cannot convert parameter 1 from 'void (__thiscall Main::* )(const char *)' to 'Helper::SIMPLECALLBK'
1> There is no context in which this conversion is possible
What am I missing here?
Main::SessionHelper is a non static method. So add static to it to be able to use it as function pointer. Or use member method pointer (you will need a instance to call it).
if you use c++11 you can use std::bind
class Helper
{
public:
void NotifyHelperbk(std::function<void(char*)> func){
/* Do your stuff */
func("your char* here");
}
And your main :
Main.cpp
Main m;
helper.NotifyHelperbk(std::bind(&Main::SessionHelper, m, std::placeholder_1));

c++ unordered_multimap insert hash

I'm going crazy over here. I have search google to find 1 single decent example where people use a unordered_map together with enum class and a hash function without any luck. Those i manage to find always end up saying "use map instead".
I'm trying to do the following:
Enum class facing is the direction my sprite is looking at.
Enum class Action is the action my sprite is doing.
Animation is a class that holds different animations which i will call later.
The container should look like this:
map
There can be more than 1 FACING in the map as key and there can be more than one ACTION in the pair.
Example:
map<LEFT, pair<ATTACK, attackAnimation>
map<LEFT, pair<IDLE, idleAnimation>
map<LEFTUP, pair<IDLE, idleAnimation>
This is an simplified everything
#include <iostream>
#include <unordered_map>
#include <string>
#include <memory>
template <typename T>
struct Hash
{
typedef typename std::underlying_type<T>::type underlyingType;
typedef typename std::hash<underlyingType>::result_type resultType;
resultType operator()(const T& arg) const
{
std::hash<underlyingType> hasher;
return hasher(static_cast<underlyingType>(arg));
}
};
class Animation
{
private:
std::string str;
public:
Animation(std::string _string)
{
this->str = _string;
}
std::string& GetString()
{
return this->str;
}
};
class Bullshit
{
public:
enum class Action
{
Attack,
Move
};
enum class Facing
{
Right,
Up,
Left
};
Bullshit()
{
}
std::unordered_multimap<Bullshit::Facing, std::pair<Bullshit::Action, std::unique_ptr<Animation>>,Hash<Bullshit::Facing>>& GetlistAnimation()
{
return this->listAnimation;
}
private:
std::unordered_multimap<Bullshit::Facing, std::pair<Bullshit::Action, std::unique_ptr<Animation>>,Hash<Bullshit::Facing>> listAnimation;
};
int main()
{
Bullshit bull;
auto myList = bull.GetlistAnimation();
std::unique_ptr<Animation> anim(new Animation("test"));
myList.insert(std::make_pair(Bullshit::Facing::Up, std::make_pair(Bullshit::Action::Attack, std::move(anim))));
std::cin.get();
return 0;
}
Error code:
error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
1> with
1> [
1> _Ty=Animation
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\memory(1447) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr'
1> with
1> [
1> _Ty=Animation
1> ]
1> This diagnostic occurred in the compiler generated function 'std::pair<_Ty1,_Ty2>::pair(const std::pair<_Ty1,_Ty2> &)'
1> with
1> [
1> _Ty1=Bullshit::Action,
1> _Ty2=std::unique_ptr<Animation>
1> ]
Here
auto myList = bull.GetlistAnimation();
the type deduced for myList is std::unordered_map<.....>, that is, it's not a reference. And the copy can't be created because the map contains unique_ptrs. What you meant is
auto& myList = bull.GetlistAnimation();
or in C++14,
decltype(auto) myList = bull.GetlistAnimation();
The problem has nothing to do with unordered_map or hash functions. It's the std::unique_ptr, which is uncopyable, and your GetlistAnimation attempts to copy it (indirectly).
How to correctly fix this depends on what you want to achieve.
A quick fix would be to use std::shared_ptr instead:
std::unordered_map<Bullshit::Facing, std::pair<Bullshit::Action, std::shared_ptr<Animation>>,Hash<Bullshit::Facing>>& GetlistAnimation()
{
return this->listAnimation;
}
private:
std::unordered_map<Bullshit::Facing, std::pair<Bullshit::Action, std::shared_ptr<Animation>>,Hash<Bullshit::Facing>> listAnimation;
[...]
std::shared_ptr<Animation> anim(new Animation("test"));
myList.insert(std::make_pair(Bullshit::Facing::Up, std::make_pair(Bullshit::Action::Attack, anim)));
(By the way, you should use std::make_shared and std::make_unique.)
A fix which may be quick and correct (again, depending on what you want to achieve) is to get rid of the pointer logic altogether and just use Animation directly:
std::unordered_map<Bullshit::Facing, std::pair<Bullshit::Action, Animation>,Hash<Bullshit::Facing>>& GetlistAnimation()
{
return this->listAnimation;
}
private:
std::unordered_map<Bullshit::Facing, std::pair<Bullshit::Action, Animation>,Hash<Bullshit::Facing>> listAnimation;
[...]
Animation anim("test");
myList.insert(std::make_pair(Bullshit::Facing::Up, std::make_pair(Bullshit::Action::Attack, anim)));

How to connect signal to boost::asio::io_service when posting work on different thread?

I'm trying to use a boost::lockfree queue to manage tasks. These tasks retrieve data and would be processed on a worker thread. Once data is retrieved, a signal should be sent to the main thread with the data. The worker thread is spawned at the start of the application and just keeps polling the queue. I'm new to Boost::Asio but from my research, it seems to be the best mechanism for sending signals between threads.
I've looked at several examples, in particular:
Confused when boost::asio::io_service run method blocks/unblocks
boost asio post not working , io_service::run exits right after post
Here is my code:
#include "stdafx.h"
#include <thread>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/optional.hpp>
#include <boost/thread.hpp>
#include <boost/signals2.hpp>
typedef boost::signals2::signal<void(int)> signal_type;
class Task
{
public:
Task(int handle) : _handle(handle) {};
~Task() {};
virtual void Execute()
{
int result = _handle * 2;
}
private:
int _handle;
};
class Manager
{
public:
Manager()
{
_mainService = std::make_shared<boost::asio::io_service>();
_workerService = std::make_shared<boost::asio::io_service>();
_work = std::make_shared<boost::asio::io_service::work>(*_workerService);
_threadStarted = false;
Start();
};
~Manager() {};
void WorkerMain()
{
_workerService->poll();
}
void Start()
{
if (_threadStarted) return;
_workerThread = std::thread(&Manager::WorkerMain, this);
_threadStarted = true;
}
void Stop()
{
if (_threadStarted == false) return;
_mainService->stop();
_workerThread.join();
_mainService.reset();
}
void OnSignalFetchCompleted(int value)
{
int asdf = 0; //do stuff with data on main thread
}
void ProcessData(signal_type& signal)
{
int i = 0;
do
{
_queue.consume_one([&](std::shared_ptr<Task> task)
{
task->Execute();
//get data from task; send out signal with data
});
i++;
} while (i < 3);
}
void QueueData(int handle)
{
_signalFetchCompleted.connect(boost::bind(&Manager::OnSignalFetchCompleted, this, _1));
_workerService->post(boost::bind(&Manager::ProcessData, boost::ref(_signalFetchCompleted))); //!!does not compile
std::shared_ptr<Task> task = std::make_shared<Task>(handle);
_queue.push(task);
}
private:
boost::lockfree::spsc_queue<std::shared_ptr<Task>, boost::lockfree::capacity<1024>> _queue;
std::thread _workerThread;
bool _threadStarted;
std::shared_ptr<boost::asio::io_service> _mainService;
std::shared_ptr<boost::asio::io_service> _workerService;
std::shared_ptr<boost::asio::io_service::work> _work;
signal_type _signalFetchCompleted;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::shared_ptr<Manager> mgr = std::make_shared<Manager>();
mgr->QueueData(5);
mgr->QueueData(10);
mgr->Stop();
return 0;
}
I'm getting a compile error on the _workerService->Post line that I haven't been able to resolve:
1>C:\Boost\boost/bind/mem_fn.hpp(333): error C2784: 'T *boost::get_pointer(const boost::scoped_ptr<T> &)' : could not deduce template argument for 'const boost::scoped_ptr<T> &' from 'const signal_type'
1> C:\Boost\boost/smart_ptr/scoped_ptr.hpp(150) : see declaration of 'boost::get_pointer'
1> C:\Boost\boost/bind/mem_fn.hpp(352) : see reference to function template instantiation 'R (__cdecl &boost::_mfi::dm<R,Manager>::call<const U>(U &,const void *) const)' being compiled
1> with
1> [
1> R=void (signal_type &)
1> , U=signal_type
1> ]
1> C:\Boost\boost/bind/mem_fn.hpp(352) : see reference to function template instantiation 'R (__cdecl &boost::_mfi::dm<R,Manager>::call<const U>(U &,const void *) const)' being compiled
1> with
1> [
1> R=void (signal_type &)
1> , U=signal_type
1> ]
1> C:\Boost\boost/bind/bind.hpp(243) : see reference to function template instantiation 'R (__cdecl &boost::_mfi::dm<R,Manager>::operator ()<T>(const U &) const)' being compiled
1> with
1> [
1> R=void (signal_type &)
1> , T=signal_type
1> , U=signal_type
1> ]
Any help resolving this compile error or general comments on this approach would be greatly appreciated. Thanks.
In light of new information, the problem is with your boost::bind. You are trying to call a member function without an object to call it on: you are trying to call ProcessData but you haven't told the bind on which object you wish to call it on. You need to give it a Manager to call it on:
_workerService->post(boost::bind(&Manager::ProcessData, this, boost::ref(_signalFetchCompleted)));
This will call ProcessData on this and pass in a reference to _signalFetchCompleted
The compiler error seems to be talking about you constructing a boost::asio::io_service::work object and that you are passing it incorrect parameters:
error C2664: 'boost::asio::io_service::work::work(const boost::asio::io_service::work &)' : cannot convert argument 1 from 'std::shared_ptr<boost::asio::io_service>' to 'boost::asio::io_service &'
boost::asio::io_service::work has a constructor which takes a boost::asio::io_service& and a copy constructor; however, you are passing it a std::shared_ptr<boost::asio::io_service>:
_work = std::make_shared<boost::asio::io_service::work>(_workerService);
Here, _workerService is a std::shared_ptr<boost::asio::io_service>, but you need a boost::asio::io_service&. Try the following instead:
_work = std::make_shared<boost::asio::io_service::work>(*_workerService);
I think that boost::asio is not the best solution for your task. Have you read about conditional variables? They are much more simple and can be used to achieve your goal.

c++ - Function pointer object seems not to to exist

I'm writing some kind of libary which organizes and keeps track of some tasks. Whenever a nwe task is called my libary uses a function pointer given in the constructor. But when I try to call it I get the error Symbol not found
In the Header file I declared it as:
template <class T>
class TaskManager
{
private:
// other variables
T TaskID; // This is defined like this (just to clear things up)
void (*TaskHandler)(T, TaskManager<T>*);
// some more stuff
};
I call it like
template <class T>
void TaskManager<T>::startActualTask()
{
(*TaskManager<T>::TaskHander)(TaskID, this); // Errors!
}
or
template <class T>
void TaskManager<T>::startActualTask()
{
TaskManager<T>::TaskHander(TaskID, this); // Errors!
}
(Removing TaskManager<T>:: in front of ´TaskHander(TaskID, this);´ did not help.)
But it cannot find the symbol TaskHandler. No matter what i tried so far!
The full error is:
e:\eigene dateien\visual studio 2010\projects\brainstonemod - publish\brainstonemod - publish\TaskManager.cpp(212): error C2039: 'TaskHander': Is no element of 'TaskManager<T>'
with
[
T=int
]
e:\eigene dateien\visual studio 2010\projects\brainstonemod - publish\brainstonemod - publish\TaskManager.cpp(211): At the compiling of the class template of the void TaskManager<T>::startActualTask(void) member function
with
[
T=int
]
e:\eigene dateien\visual studio 2010\projects\brainstonemod - publish\brainstonemod - publish\TaskManager.cpp(73): At the compiling of the class template of the void TaskManager<T>::addTask(Task<T>) member function
with
[
T=int
]
e:\eigene dateien\visual studio 2010\projects\brainstonemod - publish\brainstonemod - publish\TaskManager.cpp(9): At the compiling of the class template of the TaskManager<T>::TaskManager(std::wstring,std::wstring,void (__cdecl *)(T,TaskManager<T> *)) member function
with
[
T=int
]
main.cpp(14): See the Instatiation of the just compiled class template "TaskManager<T>".
with
[
T=int
]
(I had to translate this. So it might not be acurate translated!)
This might also be interesting:
template <class T>
TaskManager<T>::TaskManager(wstring title, wstring subtitle, void (*taskHandler)(T, TaskManager<T>*)) :
// Some intatiations
{
TaskHandler = taskHandler;
// More contructor stuff
}
How could i solve this?
If it's an ordinary member that is a function pointer (which is what it seems to be in your class declaration), you should call it like:
template <class T>
void TaskManager<T>::startActualTask()
{
TaskHandler(TaskID, this);
}
You only use the TaskManager<T>:: prefix for static members or typedefs.
It's a typo. I spelled it TaskHander but it's TaskHandler (I forgot the l)
Thank you anyways!