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!
Related
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)));
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());
}
I've specified a header file like this:
04-Templates_foo.h:
template <typename T>
class foo {
T x, y;
T getX(void);
void setX(T x);
};
And an implementation like this:
04-Templates_foo.cc:
#include "04-Templates_foo.h"
template <typename T>
T foo::getX(void) {
return this->x;
}
void foo::setX(T x) {
this->x = x;
}
My main routine:
04-Templates.cc
#include <iostream>
#include "04-Templates_foo.cc"
int main (void) {
// Do nothing because it doesn't even compile...
}
Compiling this code returns this error:
In file included from 04-Templates.cc:2:
./04-Templates_foo.cc:4:3: error: expected a class or namespace
T foo::getX(void) {
^
1 error generated.
I can't imagine what the problem is. Why can't I specify the function foo::getX? It's a class name, although the compiler said it is expecting a class and didn't find one :-/
If it may be important. I'm compiling this on a MacBook Pro Retina Mid 2012 with Mavericks.
I used this compile-command:
g++ -o 04-Templates 04-Templates.cc
Suggestions for a better title are welcome ;)
In the definition of foo::getX (and setX as well), what kind of foo?
Because it's a template class, you have to specify that, like
template<typename T>
T foo<T>::getX(void) { ... }
You also have to tell the compiler that member functions are templates for each function in a templated class. So you have to do it for setX as well:
template<typename T>
void foo<T>::setX(T x) { ... }
I have a C++/Win32/MFC project in Visual Studio 2008, and I'm getting a strange error message when I compile it.
I've created a small project to demonstrate the problem, and the main code is
#ifndef _MyObject_h
#define _MyObject_h
class MyObject
{
public:
MyObject()
{
}
};
#endif // _MyObject_h
// --- END MyObject.h
// --- BEGIN ObjectData.h
#ifndef _ObjectData_h
#define _ObjectData_h
template <typename DataPolicy>
class ObjectData
{
public:
DataPolicy *data;
ObjectData() :
data(NULL)
{
}
ObjectData(const ObjectData<DataPolicy> ©) :
data(copy.data)
{
}
ObjectData<DataPolicy> & operator=(const ObjectData<DataPolicy> ©)
{
this->data = copy.data;
return *this;
}
};
#endif // _ObjectData_h
// --- END ObjectData.h
// --- BEGIN Tool.h
#ifndef _Tool_h
#define _Tool_h
#include "ObjectData.h"
template <typename ObjectPolicy>
class Tool
{
private:
ObjectData<typename ObjectPolicy> _object;
public:
Tool(ObjectData<typename ObjectPolicy> obj);
};
#endif // _Tool_h
// --- END Tool.h
// --- BEGIN Tool.cpp
#include "stdafx.h"
#include "Tool.h"
template <typename ObjectPolicy>
Tool<ObjectPolicy>::Tool(ObjectData<typename ObjectPolicy> obj) :
_object(obj)
{
}
// --- END Tool.cpp
// --- BEGIN Engine.h
#ifndef _Engine_h
#define _Engine_h
#include "Tool.h"
#include "MyObject.h"
class Engine
{
private:
MyObject *_obj;
public:
Engine();
~Engine();
void DoSomething();
};
#endif // _Engine_h
// --- END Engine.h
// --- BEGIN Engine.cpp
#include "stdafx.h"
#include "Engine.h"
Engine::Engine()
{
this->_obj = new MyObject();
}
Engine::~Engine()
{
delete this->_obj;
}
void Engine::DoSomething()
{
ObjectData<MyObject> objData;
objData.data = this->_obj;
// NEXT LINE IS WHERE THE ERROR OCCURS
Tool< ObjectData<MyObject> > *tool = new Tool< ObjectData<MyObject> >(objData);
}
// --- END Engine.cpp
Errors:
Engine.cpp
c:\projects\myproject\myproject\engine.cpp(18) : error C2664: 'Tool::Tool(ObjectData)' : cannot convert parameter 1 from 'ObjectData' to 'ObjectData'
with
[
ObjectPolicy=ObjectData,
DataPolicy=ObjectData
]
and
[
DataPolicy=MyObject
]
and
[
DataPolicy=ObjectData
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>Build log was saved at "file://c:\Projects\MyProject\MyProject\Debug\BuildLog.htm"
MyProject - 1 error(s), 0 warning(s)
Thanks for any help.
There are a few problems with your code. First of all, you are using the typename keyword in a wrong way. typename can be used only when qualified type names are used (and is required when the type names are dependent), which is not your case:
template <typename ObjectPolicy>
class Tool
{
private:
ObjectData<typename ObjectPolicy> _object; // "typename" is not needed!
public:
Tool(ObjectData<typename ObjectPolicy> obj); // "typename" is not needed!
};
The problem you complain about, however, is in your instantiation of the Tool class template:
Tool< ObjectData<MyObject> > *tool = new Tool< ObjectData<MyObject> >(objData);
Your Tool<> template contains a member variable of type ObjectData<ObjectPolicy>, where ObjectPolicy is the class template parameter. However, in the line above you instantiate Tool with ObjectData<MyObject> as a parameter. This means your member variable will have type ObjectData<ObjectData<MyObject>>, and this will also be the type of the constructor's parameter.
Because of this, you are trying to invoke a constructor which accepts an ObjectData<ObjectData<MyObject>> with an argument of a mismatching type ObjectData<MyObject>. Hence, the error you get.
You should change your instantiation into:
Tool< MyObject > *tool = new Tool< MyObject >(objData);
Another problem is that you have the definition of Tool's member functions in a separate .cpp files. You should not do that: the linker won't be able to see it when processing a separate translation unit.
To solve this problem, put the definitions of your class template's member functions into the same header where the class template is defined (Tool.h in your case).
Tool< ObjectData<MyObject> > *tool = new Tool< ObjectData<MyObject> >(objData);
template <typename ObjectPolicy>
Tool<ObjectPolicy>::Tool(ObjectData<typename ObjectPolicy> obj) :
_object(obj)
{
}
It seems to me you might not really understand how templates work.
Check out the following C++ Templates
What you currently have is invalid C++ syntax. Take a look and give it another shot.
I have a problem with a template and pointers ( I think ). Below is the part of my code:
/* ItemCollection.h */
#ifndef ITEMCOLLECTION_H
#define ITEMCOLLECTION_H
#include <cstddef>
using namespace std;
template <class T> class ItemCollection
{
public:
// constructor
//destructor
void insertItem( const T );
private:
struct Item
{
T price;
Item* left;
Item* right;
};
Item* root;
Item* insert( T, Item* );
};
#endif
And the file with function defintion:
/* ItemCollectionTemp.h-member functions defintion */
#include <iostream>
#include <cstddef>
#include "ItemCollection.h"
template <class T>
Item* ItemCollection <T>::insert( T p, Item* ptr)
{
// function body
}
Here are the errors which are generated by this line of code:
Item* ItemCollection <T>::insert( T p, Item* ptr)
Errors:
error C2143: syntax error : missing ';' before '*'
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C2065: 'Type' : undeclared identifier
error C2065: 'Type' : undeclared identifier
error C2146: syntax error : missing ')' before identifier 'p'
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C2470: 'ItemCollection::insert' : looks like a function definition, but there is no parameter list; skipping apparent body
error C2072: 'ItemCollection::insert': initialization of a function
error C2059: syntax error : ')'
Any help is much appreciated.
The short answer is what Alexey already posted:
template <typename T>
typename ItemCollection<T>::Item* ItemCollection<T>::insert( T p, Item * ptr ) {
// ...
}
(To understand why typename is required, search SO for related questions, or else drop a comment. I will focus the answer in the lookup rules that explain why the return and the argument types must be declared differently)
The explanation is that the lookup rules in c++ have different scopes for the return type and the rest of the parameters. When the compiler sees the definition A B::c( D ), A is checked in the enclosing namespace of the definition, as is B. When the compiler finds ::c it looks up c inside class B. At that point, the rest of the definition is inside the scope of the class B for the rest of parameters. That means that if the return type is an internal type of the class, you have to use the qualified name for the return type, while in the case of D the compiler will first look it up inside the class B.
That explains why the return type must be fully qualified even if the last parameter is not. When the parameter Item * ptr is found by the compiler, it is already in the scope of the class, and it will find it there. On the other hand, there is no Item defined in the enclosing namespace.
One of the changes in the upcomming standard will deal with this, even if it was not designed with this purpose in mind. If I recall correctly, the following syntax should compile without the full type qualification:
template <T>
auto ItemCollection<T>::insert( T p, Item * ptr ) -> Item *
{
return 0;
}
The reason is exactly the same. After ItemCollection<T>::insert has been parsed the remainder tokens will be verified inside the ItemCollection<T> scope, including the -> Item * return definition.
template <class T>
typename ItemCollection <T>::Item* ItemCollection<T>::insert( T p, Item* ptr)
{
// function body
}