C++ compile time dispatch abstraction? - c++

#include <iostream>
struct object1 {
object1(int v) : type(1), value(v) {}
int type;
int value;
};
struct object2 {
object2(int v) : type(2), value(v) {}
int type;
int value;
};
template <typename HeaderType>
void foo(HeaderType * hdr) {
std::cout << "foo called with type " << hdr->type << " and value " << hdr->value << std::endl;
}
// this function doesn't work
template <typename HandlerType>
void dispatch(int type, int val, HandlerType handler) {
if (type == 1) {
object1 h(val);
handler(&h);
} else {
object2 h(val);
handler(&h);
}
}
int main() {
int type = 1;
int val = 1;
// this part works
if (type == 1) {
object1 h(val);
foo(&h);
} else {
object2 h(val);
foo(&h);
}
// trying to replicate the above behavior in a more abstract way,
// ideally via a function call of the following sort
//
// dispatch(type, val, ..foo..? );
}
The above program takes an input value, uses it to decide what type of object to create, then calls a function foo with a pointer to that object.
Question: Is it possible to create this sort of abstraction where the caller of dispatch doesn't know the exact types that foo will be called with but the dispatch function doesn't know the specific function that is going to be called?

With
template <typename HandlerType>
void dispatch(int type, int val, HandlerType handler) {
if (type == 1) {
object1 h1(val);
handler(&h1);
} else {
object2 h2(val);
handler(&h2);
}
}
All branches should be valid, so handler(&h1) and handler(&h2) should be valid calls.
For that, handler may be a generic lambda (since C++14) as suggested in comment:
dispatch(type, val, [](auto a) {return foo(a);} );
or you may create your own functor:
struct foo_caller
{
template <typename HeaderType>
void operator () (const HeaderType* hdr) const {
std::cout << "foo called with type " << hdr->type << " and value " << hdr->value << std::endl;
}
};
And then call it:
dispatch(type, val, foo_caller());

Related

C++: How to use different dynamic template in map

my header code:
template <typename T>
class A
{
}
template<> class A<short>;
template<> class A<float>;
in my cpp, i want to use a map to contain different type a, like following code:
class B
{
map<int, A*> a; /* how to declare a */
public:
AddA(int key, int type)
{
if (type == 1)
{
a.insert({ key, new A<short>() });
}
else
{
a.insert({ key, new A<float>() });
}
}
template<typename T>
func(int key, T v)
{
a[key].func(v);
}
};
question: how to implement it?
edit # 0410, here is my solution:
class ABase
{
virtual void func(void* t)=0;
}
template <typename T> A;
template <short> A : public ABase
{
void func(void* t) override
{
auto value = *static_cast<short*>(t);
// do processing
}
template <float> A : public ABase
{
void func(void* t) override
{
auto value = *static_cast<float*>(t);
// do processing
}
CPP: used a map of ABase* for all the template class, and use a virtual func for all template interface
main()
{
map<int, ABase*> objs;
objs.insert({0, new A<short>()});
objs.insert({1, new A<float>()});
auto value=0;
objs[0]->func(&value);
auto value1=0.f;
objs[1]->func(&value1);
}
If you really need to have multiple types in a single map, you can use a map of std::variant. But as already mentioned in the comments, this might be a design problem.
But if you need it, you can proceed with the std::map< int, std::variant<>>. Later on, if you want to access the stored element, you have to call std::visit to pick the element which is stored in std::variant.
See the following example:
template < typename T >
struct A
{
};
// spezialize if needed, here only for demonstration purpose
template <> struct A<short> { void func(short parm) { std::cout << "A<short> with " << parm << std::endl; } };
template <> struct A<float> { void func(float parm) { std::cout << "A<float> with " << parm << std::endl; } };
class B
{
std::map<int, std::variant<A<short>*, A<float>*>> a;
public:
void AddA(int key, int type)
{
if (type == 1)
{
a.insert({ key, new A<short>() });
}
else
{
a.insert({ key, new A<float>() });
}
}
template<typename T>
void func(int key, T v)
{
std::visit( [&v]( auto ptr ) { ptr->func(v); }, a[key] );
}
};
int main()
{
B b;
b.AddA( 1, 1 );
b.AddA( 2, 2 );
b.func( 1, 99 );
b.func( 2, 100 );
}
You can't achieve the problem with templates. Template declaration is only a blueprint for a type candidate.
"A<short>" is the type not "A" itself.
You can achieve your problem through inheritance.
Edit: Code is updated according to #MSalters' comment. Thanks.
#include <iostream>
#include <map>
class A
{
public:
virtual void func(void* x) = 0;
};
class A_Short : public A
{
public:
void func(void* x)
{
short* value = static_cast<short*>(x);
std::cout << "short value: " << *value << std::endl;
}
};
class A_Float : public A
{
public:
void func(void* x)
{
float* value = static_cast<float*>(x);
std::cout << "float value: " << *value << std::endl;
}
};
template<typename T>
class A_Derived : public A
{
public:
void func(void* x)
{
T* value = static_cast<T*>(x);
std::cout << "[Derived] value: " << *value << std::endl;
}
};
class B
{
std::map<int, A*> a; /* how to declare a */
public:
void AddA(int key, int type)
{
if (type == 1)
{
a.insert({ key, new A_Short() });
}
else if(type == 2)
{
a.insert({key, new A_Derived<short>()});
}
else if(type == 3)
{
a.insert({key, new A_Derived<float>()});
}
else
{
a.insert({ key, new A_Float() });
}
}
// Assumes that user knows to use which T for any "key"
template<typename T>
void func(int key, T v)
{
a[key]->func(v);
}
};
int main()
{
B b;
b.AddA(1, 1);
b.AddA(2, 8);
b.AddA(3, 2);
b.AddA(4, 3);
short s = 1;
float f = 7.1;
short s2 = 2;
float f2 = 7.2;
b.func(1, &s);
b.func(2, &f);
b.func(3, &s2);
b.func(4, &f2);
}

Calling a member function pointer in a template with implicit this

Looking at this answer I can see how to call a pointer to a member function by explicitly passing in this. However, what if I want the function passed in to be a member of the current object and to use the implicit this.
I've written this, which seems to work, but is it valid code, and is there a better way (C++14 or below) avoiding the dynamic_cast<>? Source on onlinegdb.com
#include <iostream>
class Base
{
public:
// From https://stackoverflow.com/a/9779391/1270789
template<typename T, typename R>
R proxycall(T *obj, R (T::*mf)(int))
{
return (obj->*mf)(42);
}
// My attempt
template<typename T, typename R>
R proxycall(R (T::*mf)(int))
{
return ((dynamic_cast<T *>(this))->*mf)(42);
}
virtual ~Base() {}
};
class Foo: public Base
{
public:
int doFoo(int x) { std::cout << "doing foo\n"; return x / 2; }
int doCall() { return proxycall(this, &Foo::doFoo); } // OK
int doNoThisCall() { return proxycall(&Foo::doFoo); } // Is this OK?
};
int main()
{
Foo foo;
std::cout << foo.doCall() << '\n';
std::cout << foo.doNoThisCall() << '\n';
return 0;
}

Why does variadic template parameter pack keep same size if a simple type parameter is included to the right of parameter pack?

In order to find the position of a type in a variadic template I implemented the following template:
template <class T, class ...Params, class Based>
size_t derived_index(Based* a) {
// show template instance and size of Params
std::cout << __PRETTY_FUNCTION__ << std::endl;
std::cout << sizeof...(Params) << std::endl;
// verify is a is one of the polymorphic types
if (dynamic_cast<T*>(a) != nullptr)
return 0;
else
return 1u + derived_index<Params..., Based>(a);
}
in such a way Based template parameter can be deduced, for instances:
struct Base { virtual void f() = 0; };
struct A: Base { void f() override {} };
struct B: Base { void f() override {} };
struct C: Base { void f() override {} };
struct D: Base { void f() override {} };
int main() {
Base* a = new A;
Base* c = new C;
std::cout << " index: " << derived_index<A, B, D>(c) << std::endl;
return 0;
}
I did another implementation that looks better because it detects if it was not found and return -1, so i needed to overload derived_index:
UPDATED VERSION This one works well deducing Based type.
template <class Based>
int derived_index(Based* a) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return -1;
}
template <class T, class ...Params, class Based>
int derived_index(Based* a) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
if (dynamic_cast<T*>(a) != nullptr)
return 0;
else {
auto&& index = derived_index<Params...>(a);
return index >= 0 ? 1 + index: -1;
}
}
In first version Params size keeps invariant, Does anybody know which is the reason? Is it standard?
Thanks

How to call object's methods using a function pointer?

I'd like to call a few methods of classes 'A' and 'B' from the class 'Caller'. I need to use a function pointer because I want to call different methods.
My method gets called, but when I try to access a member variable from it, my program crashes ('program.exe has stopped working').
How come that happens?
#include <iostream>
using namespace std;
template <class T>
class Caller
{
typedef void (T::*myFunc)(int);
public:
Caller(T* obj, myFunc fp)
{
f = fp;
}
void invoke(int foobar)
{
(o->*f)(foobar);
}
private:
myFunc f;
T* o;
};
class A
{
public:
A() : n(0) {}
void foo(int bar)
{
cout << "A::foo called (bar = " << bar << ", n = " << n << ")" << endl; // the crash occurs here, and 'this' equals 0 at this point
}
void setNum(int num)
{
n = num;
}
private:
int n;
};
class B
{
public:
B() : n(0) {}
void fooo(int bar)
{
cout << "B::fooo called (bar = " << bar << ", n = " << n << ")" << endl; // same here if I call B::fooo first
}
void setNum(int num)
{
n = num;
}
private:
int n;
};
int main()
{
A myA;
B myB;
myA.setNum(128);
myB.setNum(256);
Caller<A> cA(&myA, &A::foo);
Caller<B> cB(&myB, &B::fooo);
cA.invoke(10);
cB.invoke(20);
return 0;
}
Thank you in advance.
EDIT : I use VS2017 and I can build my program without getting any compiler errors.
My method gets called, but when I try to access a member variable from it, my program crashes ...
Because you forgot to assign passed obj to o pointer in your Caller:
template <class T>
class Caller
{
typedef void (T::*myFunc)(int);
public:
Caller(T* obj, myFunc fp)
{
o = obj; // << == you need this!
f = fp;
}
void invoke(int foobar)
{
(o->*f)(foobar);
}
private:
myFunc f;
T* o;
};
Also, in general it's better to use member initializer lists:
Caller::Caller(T* obj, myFunc fp) : o(obj), f(fp)
{
}

functor call (additional characters)

I tried to build a minimal example:
struct Functor
{
void operator()(int& a)
{
a += 1;
}
void other(int& a)
{
a += 2;
}
};
template <typename foo>
class Class
{
public:
void function()
{
int a = 10;
foo()(a);
std::cout << a << std::endl;
}
};
int main()
{
Class<Functor> c;
c.function();
}
My question about this: Why is it even possible to call the operator on the pure type without an object? How can I call the function other the same way as I call operator()?
You're not calling it on a pure type. foo() invokes the constructor, and evaluates to a temporary foo object, on which you then invoke operator().
To do the equivalent with a "normal" member function, just do:
foo().other(a);
You are not "call[ing] the operator on the pure type without an object". The syntax foo()(a) is creating a temporary of type foo (this is the foo() part) and then calling operator() on that object with a as argument: (the (a) part).
Pure type example:
struct Functor
{
void operator()(int& a)
{
a += 1;
}
void other(int& a)
{
a += 2;
}
static void one_more(int& a)
{
a += 3;
}
};
template <typename foo>
class Class
{
public:
void function()
{
int a = 10;
foo()(a);
foo().other(a);
foo::one_more(a);
std::cout << a << std::endl;
}
};
int main()
{
Class<Functor> c;
c.function();
}