I have a class that it has a templated function
class DialogManager
{
public:
template<class T>
using TimeoutCallback = std::function<void (T)>;
DialogManager();
virtual ~DialogManager();
template<class T>
void SetTimeoutCallback(TimeoutCallback<T> callback);
int GetDialoge(T obj);
private:
TimeoutCallback mTimeoutCallback;
}
I get below error:
error: invalid use of template-name ‘DialogManager::TimeoutCallback’
without an argument list
I've changed code to
template<class T>
TimeoutCallback<T> mTimeoutCallback;
but I a got another compiler's error
error: data member ‘mTimeoutCallback’ cannot be a member template
example usage is
#include <DialogManager.h>
class foo()
{
public:
foo()
{
DialogManager* dialog = new DialogManager();
}
DialogManager* mDialogManager;
};
struct data
{
data() {}
};
int main()
{
Foo* f1 = new Foo();
auto a1 = f1->mDialogManager->GetDialoge(1);
auto b1 = f1->mDialogManager->GetDialoge("test");
Foo* f2 = new Foo();
data d;
auto a2 = f2->mDialogManager->GetDialoge(d);
auto b2 = f2->mDialogManager->GetDialoge(45.231);
return 0;
}
`
If you want to share the same template type in different parts of class, make it template class instead of template function.
#include <functional>
template<class T>
class DialogManager
{
public:
using TimeoutCallback = std::function<void (T)>;
DialogManager();
virtual ~DialogManager();
void SetTimeoutCallback(TimeoutCallback callback);
private:
TimeoutCallback mTimeoutCallback;
};
If you are writing a class header file, then you generally want to template the class and use the template type's name as a variable type within that file. Then, inside the coder file, you can define the methods similar to how you were in the code your provided. It looks like you fixed the first compilation error, and the second error seems to be because you are templating individual methods within the header file. Here is a basic example for templating a header file:
`template<typename T>
class Node{
private:
T m_entry;
Node<T>* m_nextNodePtr;
public:
T getEntry() const;
void setEntry(T newEntry);
//more
}`
And here is the header file's accompanying coder file:
`template<typename T>
T Node<T>::getEntry() const{
return m_entry;
}
template<typename T>
void Node<T>::setEntry(T newEntry){
m_entry = newEntry;
return;
//more
}`
Hope this helps!
Your mTimeoutCallback is a template member variable; resolving the using, it's a
template<class T>
std::function<void (T)> mTimeoutCallback;
Unfortunately (a) template variables are available only starting from C++14 (and you tagged C++11) and (b) a template variable can be member of a class/struct only if static.
So your errors.
Related
I need to build my code in MSVC(C++98). I declare a template class with template class parameter. At result I am getting an error during compilation at MSVC:
error C2977: 'Set': too many template arguments
Gcc builds this code well.
You can try it by yourself:
https://godbolt.org/z/YJXLX7
here you are this code:
#include <iostream>
#include <vector>
class Iterator
{
public:
virtual int size() = 0;
};
template <template<typename> class TContainer, class TType>
class IteratorCollectionTest
: public Iterator
{
public:
virtual int size() { m_collection.size(); }
private:
TContainer<TType> m_collection;
};
template<typename TItem>
class Set
{
public:
Set();
Iterator* createIterator();
int size();
protected:
class SetInstance;
private:
SetInstance* m_instance;
};
template<typename TItem>
class Set<TItem>::SetInstance
{
public:
Iterator* createIterator() { return new IteratorCollectionTest<Set, TItem>(); }
int size() { return m_vec.size(); }
public:
std::vector<TItem> m_vec;
};
template<typename TItem>
Set<TItem>::Set()
: m_instance(new SetInstance())
{
}
template<typename TItem>
Iterator* Set<TItem>::createIterator()
{
return m_instance->createIterator();
}
template<typename TItem>
int Set<TItem>::size()
{
return m_instance->size();
}
int main()
{
Set<int> m_serr;
Iterator* iter = m_serr.createIterator();
}
what am I doing wrong?
Can anybody help me?
Class templates have a special member, called the injected class name. Inside the scope of the class template, the template name stands for the current specialization. It does not stand for the template.
new IteratorCollectionTest<Set, TItem>() appears inside the scope of the class template Set. So MSVC assumes the Set argument does not refer to the template. It assumes that the name refers to the specialization, the type that is Set<TItem>. And therefore passes a class name where a template name is expected.
It's the behavior mandated by C++98. And that behavior has since been amended in C++11, where the template name appearing as a template argument does not refer to the injected class name. In C++11 and later mode, GCC would accept the code. But when forcing C++98 mode, it complains too.
The workaround is to qualify the name.
Iterator* createIterator() { return new IteratorCollectionTest<::Set, TItem>(); }
Since ::Set is a fully qualified name, it can refer only to the template that is at namespace scope.
I have a template class as below:
template<typename A> struct TaskInfo{
typedef A _A;
static void bar(A a){blah blah...} };
template <typename TaskInfo> class Task {
typedef typename TaskInfo::_A A;
bar(A a){
blah blah...
TaskInfo::bar(a);
}
}
and I have an object that has a collection of these classes:
using TaskInfoX= TaskInfo<int>; //ignore the bar implementation for the time being.
using TaskInfoY= TaskInfo<double>;
class TaskCollection(){
TaskCollection(){
auto Task1=new Task<TaskInfoX>;
auto Task2=new Task<TaskInfoY>;
Register(Task1);
Register(Task2);
}
Register(...);
}
I want to know if it is possible to define an enum list:
enum TaskEnum
{
Etask1,
Etask2
};
and a function getTask such that in my app I can have:
int main {
TaskCollection collection;
int testInt;
double testDouble;
collection.getTask(Etask1)->bar(testInt);
//collection.getTask(Etask1)->bar(testDouble); //want compile error.
collection.getTask(Etask2)->bar(testDouble);
}
I know that I can have CRTP or the virtual inheritance equivalent that allows me to pass variadic arguments for bar() but I want to have type checking on the parameters of the bar function at compile time. Is this impossible in C++?
Update: Apologise for the typo. That was meant to be: getTask(task1). basically the outside world doesn't know about the underlying structure of the tasks and only knows them based on their public enum keys. Also note that in general there would be additional tasks potentially reusing the typeInfoX parameter.
First, to have error if type is not an exact match, you may use the following:
template <typename T>
class Task
{
public:
using type = typename T::type;
void bar(type a) { T::bar(a); }
template <typename U>
std::enable_if_t<!std::is_same<std::decay_t<U>, type>::value>
bar(U&&) = delete;
};
Then, with some helpers:
template <TaskEnum> struct TaskMap;
template <> struct TaskMap<Etask1> { using type = Task<TaskInfoX>; };
template <> struct TaskMap<Etask2> { using type = Task<TaskInfoY>; };
Your collection could be something like:
class TaskCollection
{
public:
Task<TaskInfoX> taskX;
Task<TaskInfoY> taskY;
template <TaskEnum E>
typename TaskMap<E>::type&
getTask();
};
template <>
Task<TaskInfoX>& TaskCollection::getTask<Etask1>() { return taskX; }
template <>
Task<TaskInfoY>& TaskCollection::getTask<Etask2>() { return taskY; }
With final usage:
collection.getTask<Etask1>().bar(testInt);
collection.getTask<Etask1>().bar(testDouble);//error:call to deleted member function 'bar'
collection.getTask<Etask2>().bar(testDouble);
Demo
You can always template a concrete class with primitives. So instead of:
using TaskInfoX= TaskInfo<int>;
using TaskInfoY= TaskInfo<double>;
you can just have
template<> class Task<TaskEnum::Task1> : public TaskInfo<int>{}
template<> class Task<TaskEnum::Task2> : public TaskInfo<double>{}
and then define a template function:
template<TaskEnum taskE>
Task<taskE>* getTask() {}
You will need to derive template class Task from a base class so you can put it in a map, and you should define a map
std::map<TaskEnum,TaskBase*> taskMap;
and in getTask you can just do a static cast:
static_cast<Task<taskE>* >(taskBasePtr);
I think std::tuple is what you need:
auto my_tuple = std::make_tuple(Task<TaskInfoX>(), Task<TaskInfoY>());
std::get<Task<TaskInfoX>>(my_tuple).bar(12);
// actually, this is not an error because double can be convert to int
std::get<Task<TaskInfoX>>(my_tuple).bar(12.323);
Given the way Task1 and Task2 are stored in your TaskCollection class, I cant see an obvious way to implement getTask as a template, but you can overload it.
class TaskCollection
{
//...
Task<TaskInfoX> GetTask(Task<TaskInfoX> task)
{
return Task1;
}
Task<TaskInfoY> GetTask(Task<TaskInfoY> task)
{
return Task2;
}
};
If your real case works in with double and int then you need to supress the conversion from double to int in order to achieve this compile-time error...
//collection.getTask(Task1)->bar(testDouble); //want compile error.
one way to do this is to declare but not define a template version of bar in your TaskInfo
template<typename A> struct TaskInfo
{
static void bar(A a){blah blah...}
template<typename T> static void bar(T a); // deliberately not defined
//...
};
you still define your existing bar function for the type you do want to handle, but now, in the case that you want to fail, the compiler will try to call the template version of bar (with T as a double) in preference to calling the int version with a conversion from double to int. The resulting error in VS2015 is
error LNK2019: unresolved external symbol "public: static void __thiscall C::bar(double)
but if no code tries to call it then it doesn't matter that it is not defined an there is no error.
(It wasn't clear to me what the question was regarding the enum)
using namespace std;
#include <vector>
#include <string>
template <class T>
struct ValNode {
string id;
T value;
};
class ValTable {
public:
ValTable();
template <class T>
void add(string,T);
const bool find(string);
void remove(string);
private:
template<class T>
std::vector<ValNode<T>*> vals;
};
complier error:error: data member 'vals' cannot be a member template
i did try to use T* value in the struct, but i didnt work out.
I didnt use any of the functions in codes yet. was just trying to compling it into *.o file (with .cpp file also).
As the error says, variables (including data members) can't be templates; only classes and functions can be.
It looks like you want the table to be able to hold values of various different types, specified at run-time according to which types are passed to add(). For that, you need dynamic types, which aren't directly supported in C++. You might consider libraries like Boost.Any or Boost.Variant for that.
On the other hand, maybe you just want to store a single type in each table, and different types in different tables. In that case, the class itself will need to be a template:
template <typename T>
class ValTable {
public:
ValTable();
void add(string,T);
const bool find(string);
void remove(string);
private:
std::vector<ValNode<T>*> vals;
};
In C++ you can have template methods in a class, but not template data members.
For example:
template<typename T, int n>
struct FixedVector {
T x[n];
FixedVector() {
for (int i=0; i<n; i++) x[i] = 0;
}
template<typename C>
void copy(const C& container) {
if (container.size() != n) {
throw std::runtime_error("Wrong size");
}
int j = 0;
for (typename C::const_iterator i=container.begin(),
e=container.end();
i!=e;
++i)
{
x[j++] = *i;
}
}
};
With the above class you can declare FixedVector<int, 5> f and call f.copy(v) where v can be for example a vector or a list or anything that has size begin and end.
So FixedVector::copy is a template method and this means that the compiler will generate a different version of it for each different type you will pass to the function.
std::vector<double> y;
y.push_back(3.4); y.push_back(5.6); y.push_back(7.8);
std::list<unsigned char> z;
z.push_back('a'); z.push_back('b'); z.push_back('c');
FixedVector<int, 3> v;
v.copy(y); // This is ok
v.copy(z); // This is ok too
C++ doesn't allow template data members because this would imply a different class size depending on how many types you are using in a specific compilation unit and this doesn't go with the C++ compilation model of one-unit-at-a-time.
Adding methods is instead fine because it doesn't affect class size, and everything can be fixed at link time by avoiding pulling multiple copies of the same method from different compilation units.
You will have to declare ValTable as template
template <class T>
class ValTable{
public:
ValTable();
//template <class T>
void add(string,T);
const bool find(string);
void remove(string);
private:
//template<class T>
std::vector<ValNode<T>*> vals;
};
You won't be able to do that ValTable needs to be a template
You can have this :
template <class T> //Make the class as template
class ValTable {
public:
ValTable();
template <class X>
void add(string,X);
const bool find(string);
void remove(string);
private:
//template<class T>
std::vector<ValNode<T>*> vals;
};
You cannot have template member values: each translation unit could access different instantiations resulting in different ibject layouts. You'd need to factor out the type in some way.
The standard library does something along the lines of what you want for std::locale: each std::locale stores a collection of differently typed objects. It is soecial purpose and can't be used for your purpose directly.
The basic idea is to automatically map each type used to an int which is then used to map the type to an instance. The vals member would then be a function template looking up the correct instance. A rough outline could look like this:
int type_index_alloc() {
static std::atomic<int> current(0);
return ++current;
}
template <typename T>
int type_map() {
static int rc = type_index_alloc();
}
class container {
struct base { virtual ~base() {} };
template <typename T>
struct value: base { T v; };
std::map<int, std::shared_ptr<base>> vals_;
public:
T& vals() {
std::shared_ptr<base>& rc(vals_[type_map<T>()]);
if (!rc) {
rc = std::make_shared<value<T>>()); }
return static_cast<value<T>&>(*rc).v;
}
};
This a just trying to show how things are being set up: I currently don't have access to a compiler. Also, the code example just provides access to an object of type T but it could easily be changed to use a std::vector<T> instead.
Suppose I have a class named A
template<class T>
class A
{
protected:
static T* obj;
A() {}
~A() {}
public:
// methods...
};
// Somewhere in my source file...
template <class T> A <T*> ::obj = NULL;
For various reasons I need to declare a static member obj and gcc doesn't like them being initialized during the definition of the class (apparently you can do that with visual studio)
Anyway, how do I correctly declare obj?
You can't partially specialize objects like that. Instead, just do this:
template <class T> T * A<T>::obj = NULL;
Make sure this goes in the header file along with the class template definition!
I seem to be unable to use multiple layers of templates in the following manner,
template <typename T>
template <T value>
void printValueAsInteger()
{
printf("value as integer is %i\n", (int) value);
}
so that it could be called as:
printValueAsInteger<123>();
It results in the following error message: too many template-parameter-lists.
It works if I use template <typename T, T value> with printValueAsInteger<int, 123>(), but that requires me to explicitly specify the type. How can I make it so that printValueAsInteger<123>() prints value as integer is 123?
edit:
I'll be more specific in what I need this for. My goal is to pass a member function as a function pointer, and I thought of wrapping it using templates:
template <typename T>
template <T* instance, void (T::*method)()>
void wrappedMethod()
{
(instance->*method)();
}
void callFunction(void (*function)())
{
(*function)();
}
and then pass it like this:
Base *instance = new Derived;
callFunction(&wrappedFunction<instance, Base::method>);
edit:
Err, I just realised that I probably shouldn't (and can't) use a runtime-defined variable as a template argument. I'm now trying to work around it using a class instantiated with the otherwise template arguments and creating a template function which uses that class. Or something like that. Nope, doesn't work.
Note that I cannot change the signature of callFunction, as it's part of a third party API.
At last!
I put the following in a header,
class Callable
{
public:
virtual ~Callable() { }
virtual void call() { }
};
typedef void (*functionPtr)();
extern unsigned nextMethodId;
extern functionPtr wrappedMethods[];
extern Callable *boundMethods[];
template <unsigned I>
class MethodWrapper
{
public:
static void function();
};
template <typename T>
class Method : public Callable
{
public:
Method(T* instance, void (T::*method)());
virtual void call();
private:
T* instance;
void (T::*method)();
};
template <typename T>
Method<T>::Method(T* instance, void (T::*method)())
: instance(instance), method(method) {
}
template <typename T>
void Method<T>::call()
{
if (instance && method)
(instance->*method)();
}
template <typename T>
static functionPtr bindMethod(T* instance, void (T::*method)())
{
boundMethods[nextMethodId] = new Method<T>(instance, method);
return (void (*)()) wrappedMethods[nextMethodId++];
}
and this in a source file:
#include "<insert header name here>.h"
unsigned nextMethodId = 0;
functionPtr wrappedMethods[] = {
&MethodWrapper<0>::function,
&MethodWrapper<1>::function,
&MethodWrapper<2>::function
};
Callable *boundMethods[sizeof(wrappedMethods) / sizeof(functionPtr)];
template <unsigned I>
void MethodWrapper<I>::function()
{
boundMethods[I]->call();
}
and I could use it like this:
Base *instance = new Derived;
void (*function)() = bindMethod(instance, &Base::method);
callFunction(function);
It successfully calls the derived instance's version of the method. Sadly, the amount of methods you are allowed to bind is fixed (three in this example), but it's easily extendable.
A simple transform is having the runtime value be an argument to the constructor of a functor that holds the instance pointer and the pointer to member function. The syntax at the place of use will change from:
Base *instance = new Derived;
callFunction(&wrappedFunction<instance, Base::method>);
To:
callFunction( WrappedFunction<Base,&Base::method>( instance ) );
The implementation of the WrappedFunction type is actually simple, so I leave it as an exercise. Note that a major change in this approach is that the argument to callFunction becomes a functor, and not a function pointer.
In C++11 (or with boost) the simplest way would be not coding anything and just use the available resources. Change the signature of callFunction to:
void callFunction( function<void ()> f );
And use bind to place the call:
callFunction( bind( &Base::method, instance ) );
For your first example, you can specify int as the type of template parameter:
template <int I>
void printValueAsInteger()
{
printf("value as integer is %i\n", I);
}
For your edit, you cannot use runtime-defined variables as you have already mentioned because templates are used at compile-time. Using std::bind and std::function would make it simple:
void callFunction(std::function<void()> f)
{
f();
}
Base *instance = new Derived;
callFunction(std::bind(&Base::method, instance));
After Comment
The only way I can think of is to make your member function static:
callFunction(&Base::method); // Okay if the method is declared static
Or use a global wrapper function with a global instance:
Base *instance = new Derived; // Global
void wrapperFunction()
{
instance->method();
}
callFunction(wrapperFunction);