I have
template <void (*T)(Entity *), typename Caller>
class Updater
{
public:
Updater(Caller c):m_caller(c){}
void process(Entity * e)
{
(m_caller->*T)(e); //Is this right?
}
private:
Caller m_caller;
};
I understand I can instantiate it like
Foo f;
Updater<&Foo::Bar> updater(&f);
assuming that Foo has
void Foo::Bar(Entity *e);
but what if it has desired method tempated? Like this
template <typename T>
void Bar(T t);
how shoult I instanciate it? Like this:?
Foo f;
Updater<&Foo::Bar<Entity *>> updater(&f);
When I do this in my real code, I get
invalid template argument for ..., expected compile-time constant expression
So 2 questions:
1, is (m_caller->*T)(e); correct? If it is not, how shout i call it?
2, how can I instantiate it?
template <typename Caller, void (Caller::*Func)(Entity *)>
class Updater
{
public:
Updater(Caller *c):m_caller(c){}
void process(Entity * e)
{
(m_caller->*Func)(e); // use pointer to member operator ->*
}
private:
Caller *m_caller;
};
// call like this
Foo f;
Updater<Foo, &Foo::Bar> updater(&f);
edit:
user2k5 edited his answer, so I accepted it.
my previous msg:
Thanks to user2k5 I figured out the right working code,
working sample follows: (Foo2 can be replaced by Foo)
#include <iostream>
struct Entity { int i; };
template < typename Caller, void (Caller::*Func)(Entity *)>
class Updater
{
public:
Updater(Caller *c):m_caller(c){}
void process(Entity * e)
{
(m_caller->*Func)(e);
}
private:
Caller *m_caller;
};
struct Foo
{
void bar(Entity * e)
{
std::cout << e->i << std::endl;
}
};
struct Foo2
{
template <typename T>
void bar(T t)
{
std::cout << t->i << std::endl;
}
};
int main ()
{
Foo2 f;
Updater<Foo2, &Foo2::template bar<Entity *>> updater(&f);
Entity e;
e.i = 5;
updater.process(&e);
return 0;
}
Related
I've got an abstract class that uses variable template.
template <class T>
class Abstract
{
public:
virtual void print(T t) = 0;
};
There can be any derivatives of the class like so:
class A : public Abstract<std::string>
{
public:
void print(std::string str)
{
std::cout << str << std::endl;
}
};
class B : public Abstract<int>
{
public:
void print(int number)
{
std::cout << std::to_string(number) << std::endl;
}
};
Now I want a function to return one of these derivatives so I can execute the print method. And here is my Problem:
template (class T); // error here
Abstract<T> &f(int n) // what should the return type look like?
{
if (n == 0)
{
A a{};
return a;
}
else
{
B b{};
return b;
}
}
int main()
{
A a{f(0)};
a.print("foo");
B b{f(1)};
b.print(42);
return 0;
}
So how is it be possible to return a class with unknown parameter type and call its methods?
I already tried returning derived classes without templates which works fine. As soon as templates are added code wont compile. I also tried void* and reinterpret_cast. Problem here is that I have manually to decide to what type to cast to.
So how can I return an arbitrary superclass of an abstract generic class and call its generic methods?
I think inheritance is the wrong approach here. Instead I would use specialization instead:
template<typename T>
struct Foo;
template<>
struct Foo<std::string>
{
void print(std::string const& s)
{
std::cout << s << '\n';
}
};
template<>
struct Foo<int>
{
void print(int value)
{
std::cout << value << '\n';
}
};
Then you don't need a selector to pick the object to create, just the correct type:
int main()
{
Foo<std::string> f1;
f1.print("hello");
Foo<int> f2;
f2.print(123);
}
If you really need a factor function, then it could be created like this:
template<typename T>
Foo<T> create()
{
return Foo<T>();
}
And use like
int main()
{
auto f1 = create<std::string>();
f1.print("hello");
auto f2 = create<int>();
f2.print(123);
}
How can I do something like this? I want to create a object of class C and use parameters. To elaborate, the error here is the compiler reads this as a conversion, instead of me creating an object with parameters.
EDIT: for those who still don't understand, foobar is irrelevant. I've removed it as the error still occurs without the function.
// define foobar else where
template <class C>
class Dummy {
void foo(int bar) {
C dumdum = C(bar); // Error - '<function-style-cast>': cannot convert from initializer-list to 'C'
}
}
How does that help me?
You can make foo a function template that accepts a parameter pack to make it general.
Example program:
#include <iostream>
#include <sstream>
#include <string>
template <class C>
class Dummy {
public:
template <typename... Args>
void foo(Args... args ) {
foobar(C(args...));
}
};
struct Foo
{
Foo(int, int) {}
};
struct Bar
{
Bar(int) {}
};
struct Baz
{
};
void foobar(Foo)
{
std::cout << "In foobar(Foo)\n";
}
void foobar(Bar)
{
std::cout << "In foobar(Bar)\n";
}
void foobar(Baz)
{
std::cout << "In foobar(Baz)\n";
}
int main()
{
Dummy<Foo>().foo(10, 20);
Dummy<Bar>().foo(10);
Dummy<Baz>().foo();
}
Output:
In foobar(Foo)
In foobar(Bar)
In foobar(Baz)
Have you tried something like:
C dumdum(bar);
Or:
C dumdum{bar};
?
class C {
public:
C(int a) {}
};
template <class C>
class Dummy {
public:
void foo(int bar) {
C dumdum = C(bar);
}
};
int main() {
Dummy<C> dummy;
dummy.foo(2);
return 0;
}
I didn't see any errors.
Considering the following code:
class MyClass
{
...
};
template <typename Object>
class List
{
public:
void insert(const Object & x)
{
// call when Object is MyClass
}
void insert(const Object & x)
{
// call when Object is MyClass*
}
}
int main()
{
MyClass a;
List<MyClass> lst;
List<MyClass*> plst;
lst.insert(a);
plst.insert(new Myclass);
return 0;
}
How to tell the compiler call different methods based on if the template is a class or a pointer?
How to fix the code above?
You can use a combination of std::is_pointer and std::enable_if:
#include <type_traits>
#include <iostream>
class MyClass
{
};
template <typename Object>
class List
{
public:
template<class T=Object>
void insert(T t, typename std::enable_if<std::is_pointer<T>::value >::type* = 0)
{
std::cout << "insert pointer" << std::endl;
}
template<class T=Object>
void insert(T t, typename std::enable_if<!std::is_pointer<T>::value >::type* = 0)
{
std::cout << "insert non-pointer" << std::endl;
}
};
int main()
{
MyClass a;
List<MyClass> lst;
List<MyClass*> plst;
lst.insert(a);
plst.insert(new MyClass());
return 0;
}
Live example: https://ideone.com/CK8Zdo
This will allow you to insert both pointers and non-pointers into a pointer or non-pointer list.
If you want to restrict that, you can use this:
#include <type_traits>
#include <iostream>
class MyClass
{
};
template <typename Object>
class List
{
public:
template<class T=Object>
void insert(T t, typename std::enable_if<std::is_same<T,Object>::value&&std::is_pointer<T>::value >::type* = 0)
{
std::cout << "insert pointer" << std::endl;
}
template<class T=Object>
void insert(const T& t, typename std::enable_if<std::is_same<T,Object>::value&&!std::is_pointer<T>::value >::type* = 0)
{
std::cout << "insert non-pointer" << std::endl;
}
};
int main()
{
MyClass a;
List<MyClass> lst;
List<MyClass*> plst;
lst.insert(a);
// plst.insert(a); // compiler error
// lst.insert(new MyClass()); // compiler error
plst.insert(new MyClass());
return 0;
}
Live example: https://ideone.com/3DtBfr
I'm aware that my answer is not exactly about what you are asking, but maybe it could help.
I believe your intention is to have List class with one insert method (not two of them) and behaviour of this method should depend on your template parameter. For this
you could write a specialization of your class for pointers. Then basic template would be used for non pointer types and specialization would be used for pointer types.
Your code would look like this:
template <typename Object>
class List
{
public:
void insert(const Object & x)
{
// call when Object is MyClass
}
};
template <typename Object>
class List<Object *>
{
public:
void insert(Object * x)
{
// call when Object is MyClass*
}
};
void insert(const Object & x)
{
M_insert(x, dispatcher<std::is_pointer<Object>::value> );
}
Inside List use a dispatcher
template <bool B> class dispatcher {};
using ObjectPtr = dispatcher<true>;
using ObjectValue = dispatcher<false>;
then dispatch to M_insert:
void M_insert(const Object &p, ObjectPtr) { // Object is a pointer }
void M_insert(const Object &p, ObjectValue) { // Object is not a pointer }
Live example here. But, I'd encourage you to determine whether you really need that and possibly fix your design accordingly.
This does the trick:
template <typename Object>
class List
{
public:
template<class C = Object>
void insert(const C & x)
{
// call when Object is MyClass
std::cout << "1" << "\n" ;
}
template<class P = Object*>
void insert(P* p)
{
// call when Object is MyClass*
std::cout << "2" << "\n" ;
}
} ;
Here is a working example.
I have implemented a Policy using the CRTP. The policy requires the Base class to have a function called foo:
template<typename Base>
struct Policy<Base> {
// ...
Base* b(){ return static_cast<Base*>(this); }
void do(){ b()->foo(); }
};
I have one class called Widget that uses my policy. Widget implements foo and everything is fine:
struct Widget : Policy<Widget> {
// ...
void foo();
};
The problem: I also have a type called OldWidget that implements the functionality of foo in a function named oldFoo:
struct OldWidget : Policy<OldWidget> {
// ...
void oldFoo();
};
I don't want to modify OldWidget (besides extending it with the policy). I don't want to use an AdaptedOldWidget:
struct AdaptedOldWidget : OldWidget, Policy<AdaptedOldWidget> {
void foo(){ oldFoo(); }
};
The best would be to extend my existing policy_traits class to something like:
template<typename T>
struct policy_traits {};
template<>
struct policy_traits<Widget> {
// typedefs...
member_function_name = foo;
};
template<>
struct policy_traits<OldWidget> {
// typedefs
member_function_name = oldFoo;
};
Such that I can implement the Policy like this:
template<typename Base>
struct Policy<Base> {
// ...
Base* b() { return static_cast<Base*>(this); }
void do(){ b()->policy_traits<Base>::member_function_name(); }
};
Is there away to achieve something like this in C++?
Proposed solution: I could do the following:
template<typename Base>
struct Policy<Base> : Policy_Member_Traits<Base> {
// ...
Base* b(){ return static_cast<Base*>(this); }
void do(){ foo_wrapper(); }
};
template<typename T> struct Policy_Member_Traits { };
template<> struct Policy_Member_Traits<Widget> {
void foo_wrapper(){ static_cast<T*>(this)->foo(); }
};
template<> struct Policy_Member_Traits<OldWidget> {
void foo_wrapper(){ static_cast<T*>(this)->oldFoo(); }
};
There must be hopefully a better easier way to achieve this.
first of all: signature of all functions must be the same. then you may set a static member w/ member-function address inside of your policy_traits, so you'll be able to call desired function later (from your Policy template) using it.
typedef void (*void_memfn_type)();
template<>
struct policy_traits<Widget> {
static void_memfn_type const member_function_name = &Widget::foo;
};
template<>
struct policy_traits<OldWidget> {
static void_memfn_type const member_function_name = &OldWidget::oldFoo;
};
then:
template<typename Base>
struct Policy<Base> {
// ...
Base* b() { return static_cast<Base*>(this); }
void do(){ b()->policy_traits<Base>::(*member_function_name)(); }
};
Here's an example how specializing selectively. First, some example classes:
#include <iostream>
struct Foo
{
void foo() const { std::cout << "Foo::foo\n"; }
void bar() const { std::cout << "Foo::foo\n"; }
};
struct Biz
{
void old_foo() const { std::cout << "Fiz::old_foo\n"; }
void bar() const { std::cout << "Fiz::foo\n"; }
};
struct Fiz
{
void foo() const { std::cout << "Biz::foo\n"; }
void old_bar() const { std::cout << "Biz::old_foo\n"; }
};
Now the trait:
template <typename T> struct Dispatch
{
static void foo(T const & x) { x.foo(); }
static void bar(T const & x) { x.bar(); }
};
template <> void Dispatch<Biz>::foo(Biz const & x) { x.old_foo(); }
template <> void Dispatch<Fiz>::bar(Fiz const & x) { x.old_bar(); }
And here's a usage example:
template <typename T> void dispatch(T const & x)
{
Dispatch<T>::foo(x);
Dispatch<T>::bar(x);
}
int main()
{
Foo f;
Biz b;
Fiz c;
dispatch(f);
dispatch(b);
dispatch(c);
}
Following code does NOT work, but it expresses well what I wish to do. There is a problem with the template struct container, which I think SHOULD work because it's size is known for any template argument.
class callback {
public:
// constructs a callback to a method in the context of a given object
template<class C>
callback(C& object, void (C::*method)())
: ptr.o(object), ptr.m(method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
template<class C>
struct {
C& o;
void (C::*m)();
} ptr;
};
Is there any way to do such a thing? I mean have a non-template class callback which wraps any pointer to method?
Thanks C++ gurus!
Edit:
Please see this:
Callback in C++, template member? (2)
This is a complete working example that does what I think you're trying to do:
#include <iostream>
#include <memory>
// INTERNAL CLASSES
class CallbackSpecBase
{
public:
virtual ~CallbackSpecBase() {}
virtual void operator()() const = 0;
};
template<class C>
class CallbackSpec : public CallbackSpecBase
{
public:
CallbackSpec(C& o, void (C::*m)()) : obj(o), method(m) {}
void operator()() const { (&obj->*method)(); }
private:
C& obj;
void (C::*method)();
};
// PUBLIC API
class Callback
{
public:
Callback() {}
void operator()() { (*spec)(); }
template<class C>
void set(C& o, void (C::*m)()) { spec.reset(new CallbackSpec<C>(o, m)); }
private:
std::auto_ptr<CallbackSpecBase> spec;
};
// TEST CODE
class Test
{
public:
void foo() { std::cout << "Working" << std::endl; }
void bar() { std::cout << "Like a charm" << std::endl; }
};
int main()
{
Test t;
Callback c;
c.set(t, &Test::foo);
c();
c.set(t, &Test::bar);
c();
}
I recently implemented this:
#define UNKOWN_ITEM 0xFFFFFFFF
template <typename TArg>
class DelegateI
{
public:
virtual void operator()(TArg& a)=0;
virtual bool equals(DelegateI<TArg>* d)=0;
};
template <class TArg>
class Event
{
public:
Event()
{
}
~Event()
{
for (size_t x=0; x<m_vDelegates.size(); x++)
delete m_vDelegates[x];
}
void operator()(TArg& a)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
m_vDelegates[x]->operator()(a);
}
}
void operator+=(DelegateI<TArg>* d)
{
if (findInfo(d) != UNKOWN_ITEM)
{
delete d;
return;
}
m_vDelegates.push_back(d);
}
void operator-=(DelegateI<TArg>* d)
{
uint32 index = findInfo(d);
delete d;
if (index == UNKOWN_ITEM)
return;
m_vDelegates.erase(m_vDelegates.begin()+index);
}
protected:
int findInfo(DelegateI<TArg>* d)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
if (m_vDelegates[x]->equals(d))
return (int)x;
}
return UNKOWN_ITEM;
}
private:
std::vector<DelegateI<TArg>*> m_vDelegates;
};
template <class TObj, typename TArg>
class ObjDelegate : public DelegateI<TArg>
{
public:
typedef void (TObj::*TFunct)(TArg&);
ObjDelegate(TObj* t, TFunct f)
{
m_pObj = t;
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
ObjDelegate<TObj,TArg> *d = dynamic_cast<ObjDelegate<TObj,TArg>*>(di);
if (!d)
return false;
return ((m_pObj == d->m_pObj) && (m_pFunct == d->m_pFunct));
}
virtual void operator()(TArg& a)
{
if (m_pObj && m_pFunct)
{
(*m_pObj.*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
TObj* m_pObj; // pointer to object
};
template <typename TArg>
class FunctDelegate : public DelegateI<TArg>
{
public:
typedef void (*TFunct)(TArg&);
FunctDelegate(TFunct f)
{
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
FunctDelegate<TArg> *d = dynamic_cast<FunctDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pFunct == d->m_pFunct);
}
virtual void operator()(TArg& a)
{
if (m_pFunct)
{
(*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
};
template <typename TArg>
class ProxieDelegate : public DelegateI<TArg>
{
public:
ProxieDelegate(Event<TArg>* e)
{
m_pEvent = e;
}
virtual bool equals(DelegateI<TArg>* di)
{
ProxieDelegate<TArg> *d = dynamic_cast<ProxieDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pEvent == d->m_pEvent);
}
virtual void operator()(TArg& a)
{
if (m_pEvent)
{
(*m_pEvent)(a);
}
}
Event<TArg>* m_pEvent; // pointer to member function
};
template <class TObj, class TArg>
DelegateI<TArg>* delegate(TObj* pObj, void (TObj::*NotifyMethod)(TArg&))
{
return new ObjDelegate<TObj, TArg>(pObj, NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(void (*NotifyMethod)(TArg&))
{
return new FunctDelegate<TArg>(NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(Event<TArg>* e)
{
return new ProxieDelegate<TArg>(e);
}
use it like so:
define:
Event<SomeClass> someEvent;
enlist callbacks:
someEvent += delegate(&someFunction);
someEvent += delegate(classPtr, &class::classFunction);
someEvent += delegate(&someOtherEvent);
trigger:
someEvent(someClassObj);
You can also make your own delegates and overide what they do. I made a couple of others with one being able to make sure the event triggers the function in the gui thread instead of the thread it was called.
You need to use polymorphism. Use an abstract base class with a virtual invocation method (operator() if you please), with a templated descendant that implements the virtual method using the correct type signature.
The way you have it now, the data holding the type is templated, but the code meant to invoke the method and pass the object isn't. That won't work; the template type parameters need to flow through both construction and invocation.
#Barry Kelly
#include <iostream>
class callback {
public:
virtual void operator()() {};
};
template<class C>
class callback_specialization : public callback {
public:
callback_specialization(C& object, void (C::*method)())
: o(object), m(method) {}
void operator()() {
(&o ->* m) ();
}
private:
C& o;
void (C::*m)();
};
class X {
public:
void y() { std::cout << "ok\n"; }
};
int main() {
X x;
callback c(callback_specialization<X>(x, &X::y));
c();
return 0;
}
I tried this, but it does not work (print "ok")... why?
Edit:
As Neil Butterworth mentioned, polymorphism works through pointers and references,
X x;
callback& c = callback_specialization<X>(x, &X::y);
c();
Edit:
With this code, I get an error:
invalid initialization of non-const reference of type ‘callback&’
from a temporary of type ‘callback_specialization<X>’
Now, I don't understand that error, but if I replace callback& c with const callback& c and virtual void operator()() with virtual void operator()() const, it works.
You didn't say what errors you found, but I found that this worked:
template<typename C>
class callback {
public:
// constructs a callback to a method in the context of a given object
callback(C& object, void (C::*method)())
: ptr(object,method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
// template<class C>
struct Ptr{
Ptr(C& object, void (C::*method)()): o(object), m(method) {}
C& o;
void (C::*m)();
} ptr;
};
Note that Ptr needs a constructor as it has a reference member.
You could do without struct Ptr and have the raw members.
Tested with VS2008 express.
Improving the OP's answer:
int main() {
X x;
callback_specialization<X> c(x, &X::y);
callback& ref(c);
c();
return 0;
}
This prints "ok".
Tested on VS2008 express.
Please see this
Callback in C++, template member? (2)