Dynamic dispatch in C++ - better syntax - c++

I want to have a dynamic_call functionality in C++. It should trigger overload resolution and call the most specific function on the target class (Visitor) depending on the dynamic type of the argument. It should replace the visitor pattern and should work like the dynamic keyword in C#.
I pasted what I got so far below. I want to not have to declare the generic lambda on caller side but on the implementation of dynamic call to make it easier to use. Is this possible?
#include <iostream>
struct Base { virtual ~Base() = default; };
class A : public Base {};
class B : public Base {};
template <class... Ts>
class dynamic_call {
public:
template <class F, class Arg>
static void call(F& func, Arg& a) {
call_impl<F, Arg, Ts...>(func, a);
}
private:
template <class F, class Arg>
static void call_impl(F& /*func*/, Arg& /*a*/) {
//end of recursion => nothing more to be done
}
template <class F, class Arg, class T, class... R>
static void call_impl(F& func, Arg& a) {
T* t = dynamic_cast<T*>(&a);
if(t) {
func(*t);
}
call_impl<F, Arg, R...>(func, a);
}
};
using namespace std;
struct Visitor {
void Visit(A&) { cout << "visited for a" << endl; }
void Visit(B&) { cout << "visited for b" << endl; }
};
int main(int /*argc*/, char */*argv*/[])
{
Visitor v;
auto func = [&v](auto& a) { v.Visit(a); };
A a;
dynamic_call<A, B>::call(func, a);
B b;
dynamic_call<A, B>::call(func, b);
{
Base& base(a);
dynamic_call<A, B>::call(func, base);
}
{
Base& base(b);
dynamic_call<A, B>::call(func, base);
}
return 0;
}
I want to call it like this without the need to add the generic lambda.
dynamic_call<A,B>::call(v, a);

Here are some ideas, I am not sure what your requirements are, so they might not fit:
Change Visit into operator(). Then the call syntax reduces to dynamic_call<A,B>::call(v, a); as you required. Of course that is only possible if the interface of the visitor may be changed.
Change func(*t) in call_impl to func.Visit(*t). Then again the caller can use dynamic_call<A,B>::call(v, a); and no change to the interface of the visitor is necessary. However every visitor used with dynamic_call now needs to define Visit as visitor method. I think operator() is cleaner and follows the usual patterns, e.g. for Predicates in the standard library more.
I don't particularly like either of these because the caller always has to know the possible overloads available in the visitor and has to remember using dynamic_call. So I propose to solve everything in the visitor struct:
struct Visitor {
void Visit(A&) {
cout << "visited for a" << endl;
}
void Visit(B&) {
cout << "visited for b" << endl;
}
void Visit(Base& x) {
dynamic_call<A,B>::call([this](auto& x){Visit(x);}, x);
}
};
This can be called with v.Visit(a), v.Visit(b) and v.Visit(base). This way the user of Visitor does not need to know anything about the varying behavior for different derived classes.
If you do not want to modify Visitor, then you can just add the overload via inheritance:
struct DynamicVisitor : Visitor {
void Visit(Base& x) {
dynamic_call<A,B>::call([this](auto& x){Visit(x);}, x);
}
};
The points can be combined, for example into:
struct Visitor {
void operator()(A&) {
cout << "visited for a" << endl;
}
void operator()(B&) {
cout << "visited for b" << endl;
}
void operator()(Base& x) {
dynamic_call<A,B>::call(*this, x);
}
};
Used as v(a), v(b) and v(base).

Related

How can I return an arbitrary derived class of an abstract generic class and call its generic methods?

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);
}

Defer/cancel execution of functions and analyze their arguments

I'm trying to write external draw call optimization, and for that I need to collect hooked calls, store their arguments to analyze them later on.
I've been able to make deferred calls, and somewhat readable arguments, stored in tuple, but I need to read arguments from base class and after thorough googling I can't find anything applicable.
I'll work with array of IDelegateBase mostly, and it would be very inconvenient to convert them to Delegate<...> with full signature, when I mostly would read just one argument. Therefore, I need virtual templated method in IDelegateBase, which would return n-th argument. But virtual templated methods are impossible, so probably I'd have to have templated method in base class, which would call non-template (boost::any?) virtual method and cast it's result, I suppose. But, anyway, I can't get n-th element from tuple via runtime variable.
#include <functional>
#include <iostream>
class IDelegateBase
{
public:
virtual void invoke() { }
};
template <typename T, typename... Args>
class Delegate : public IDelegateBase
{
private:
void (*_f)(Args...);
std::tuple<Args...> _args;
public:
Delegate(T& f, Args &...args)
: _f(f), _args(args...) { }
void invoke() final
{
std::apply(_f, _args);
}
};
void a() { std::cout << "a called;\n"; }
void b(int x) { std::cout << "b called with " << x << "\n"; }
void c(int x, float y) { std::cout << "c called with " << x << ", " << y << "\n"; }
int main()
{
IDelegateBase* d = new Delegate(a);
d->invoke();
int i = 42;
d = new Delegate(b, i);
d->invoke();
i = 21;
float f = 0.999;
d = new Delegate(c, i, f);
d->invoke();
// I need something like this:
auto test = d->getArgument<float>(1);
};
Update:
Final solution with kind of type checking: https://godbolt.org/z/xeEWTeosx
You could provide a virtual function returning void* and use it in a template, but type safety goes down the drain: Should you ever get the type wrong, you'll end up with undefined behaviour.
For getting element using an index you can use a recursive helper template that compares with one index per recursive call.
class IDelegateBase
{
public:
virtual void invoke() { }
template<class T>
T const& getArgument(size_t index) const
{
return *static_cast<T const*>(getArgumentHelper(index));
}
protected:
virtual void const* getArgumentHelper(size_t index) const = 0;
};
template <typename T, typename... Args>
class Delegate : public IDelegateBase
{
private:
void (*_f)(Args...);
std::tuple<Args...> _args;
public:
Delegate(T& f, Args &...args)
: _f(f), _args(args...) { }
void invoke() final
{
std::apply(_f, _args);
}
protected:
void const* getArgumentHelper(size_t index) const override
{
return GetHelper<0>(index, _args);
}
private:
template<size_t index>
static void const* GetHelper(size_t i, std::tuple<Args...> const& args)
{
if constexpr (sizeof...(Args) > index)
{
if (index == i)
{
return &std::get<index>(args);
}
else
{
return GetHelper<index + 1>(i, args);
}
}
else
{
throw std::runtime_error("index out of bounds");
}
}
};
The use of if constexpr is needed here, since std::get does not compile if a of tuple index out of bounds is used.

Using directive and Partial Specialization

I have a templatized interface class, with a couple of implemented methods and a couple of virtual ones.
I need to specialize it in order to modify the signature of some methods, but others would remain the same.
Is there a way to bring the methods that remain the same back from the original template, either via using directive, by directly calling back to them or in another way, or I must copy/paste every single method back into the specialization?
template <typename T>
struct X {
void faa(T t) const { std::cout << t << '\n'; }
void foo() const { std::cout << "foo\n"; }
};
template <>
struct X<void> {
void faa() const { std::cout << "none\n"; }
// Something along these lines
// using X<T>::foo;
// void foo() const { X<T>::foo(); }
};
Seems so. You can't get the functions in X with different signatures using using directives. There is a better workaround than copying everything from the template to the specialization. You can use a "common base class".
template <typename T>
struct X_base {
void foo() const { std::cout << "foo\n"; }
};
template <typename T>
struct X : public X_base<T> {
void faa(T t) const { std::cout << t << '\n'; }
};
template <>
struct X<void> : public X_base<void> {
void faa() const { std::cout << "none\n"; }
};
In this way, X<void>::foo acts just like X_base<void>::foo, while X<T>::faa and X<void>::faa do not interfere with each other.

C++11 call member function on template parameter pack of base classes if present

I have checked questions that are similar. This is close, but not a duplicate.
In essence I want to call a function on a parameter pack of base classes if present. I have a C++11 way of doing this that works, but it does not feel satisfactory to me.
Can someone offer a better [i.e. better performance and less boilerplate code]:
source code:
#include <iostream>
#include <type_traits>
using namespace std;
// a class initialised with an int that can't do it
struct A
{
A(int a) : _a(a) { }
void report() const { std::cout << _a << std::endl; }
private:
int _a;
};
// a class initialised with a string that can do it
struct B
{
B(std::string s) : _b (move(s)) { }
void report() const { std::cout << _b << std::endl; }
void do_it() { std::cout << "B did it with " << _b <<"!" << std::endl; }
private:
string _b;
};
// a class initialised with an int that can do it
struct D
{
D(int d) : _d(d) { }
void report() const { std::cout << _d << std::endl; }
void do_it() { std::cout << "D did it with " << _d <<"!" << std::endl; }
private:
int _d;
};
// a class initialised with a string that can't do it
struct E
{
E(std::string s) : _e(move(s)) { }
void report() const { std::cout << _e << std::endl; }
private:
string _e;
};
// a function enabled only if T::do_it is a member function pointer
// the bool is there just to make this function more attractive to the compiler
// than the next one, below
template<class T>
auto do_it(T& t, bool)
-> typename std::enable_if<std::is_member_function_pointer<decltype(&T::do_it)>::value, void>::type
{
t.do_it();
}
// a catch-all function called when do_it<T> is not valid
// the ... is less attractive to the compiler when do_it<T>(T&, bool) is available
template<class T>
void do_it(T& t, ...)
{
}
// a compound class derived from any number of classes - I am so lazy I work hard at
// being lazy.
template<class...Templates>
struct C : public Templates...
{
// construct from a parameter pack of arbitrary arguments
// constructing each base class with one argument from the pack
template<class...Args>
C(Args&&...args)
: Templates(std::forward<Args>(args))...
{
}
// private implementation of the dispatch mechanism here...
private:
// this will call ::do_it<T>(T&, bool) if T::do_it is a member function of T, otherwise
// calls ::do_it<T>(T&, ...)
template<class T>
void may_do_it()
{
::do_it(static_cast<T&>(*this), true);
}
// calls may_do_it for the last class in the parameter pack
template<typename T1>
void multi_may_do_it()
{
may_do_it<T1>();
}
// general case for calling do_it on a parameter pack of base classes
template<typename T1, typename T2, typename...Rest>
void multi_may_do_it()
{
may_do_it<T1>();
multi_may_do_it<T2, Rest...>();
}
// calls may_do_it for the last class in the parameter pack
template<typename T1>
void multi_report() const
{
static_cast<const T1&>(*this).report();
}
// general case for calling do_it on a parameter pack of base classes
template<typename T1, typename T2, typename...Rest>
void multi_report() const
{
static_cast<const T1&>(*this).report();
multi_report<T2, Rest...>();
}
// the functions we actually wish to expose here...
public:
// disptach T::do_it for each valid T in base class list
void do_it() {
multi_may_do_it<Templates...>();
}
// dispatch T::report, which must exist for each base class
void report() const {
cout << "-- all base classes reporting:" << endl;
multi_report<Templates...>();
cout << "-- all base classes reported" << endl;
}
};
int main()
{
C<A,B, D, E> c(10, "hello", 7, "goodbye");
c.report(); // all base classes must report
c.do_it(); // all base classes that can do_it, must.
return 0;
}
output:
Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1
Executing the program....
$demo
-- all base classes reporting:
10
hello
7
goodbye
-- all base classes reported
B did it with hello!
D did it with 7!
I think this is about as boilerplate-free as you can make it.
// a function enabled only if T::do_it is a member function pointer
template<class T>
auto do_it(T* t)
-> typename std::enable_if<std::is_member_function_pointer<decltype(&T::do_it)>::value, void>::type
{
t->do_it();
}
// a catch-all function called when do_it<T> is not valid
// the const void * is less attractive to the compiler when do_it<T>(T*) is available
template<class T>
void do_it(const void *)
{
}
// a compound class derived from any number of classes - I am so lazy I work hard at
// being lazy.
template<class...Templates>
struct C : public Templates...
{
//constructor omitted
private:
using expander = int[];
public:
// disptach T::do_it for each valid T in base class list
void do_it() {
(void) expander{ 0, (::do_it<Templates>(this), 0)...};
}
// dispatch T::report, which must exist for each base class
void report() const {
cout << "-- all base classes reporting:" << endl;
(void) expander{ 0, (Templates::report(), 0)...};
cout << "-- all base classes reported" << endl;
}
};
Demo.

How to write a class that may accept a function pointer and/or functor just like a smart pointer does for custom deleter?

I'm trying to write a class that accepts a a function pointer AND/OR a functor to be user later by the class.
To illustrate better what I'd like to do:
template <typename T> class Holder {
private:
T *m_ptr;
<something> m_func;
public:
Holder(T *ptr) : m_ptr(ptr), m_func(NULL) {
}
Holder(T *ptr, <something> func) : m_ptr(ptr), m_func(func) {
}
~Holder() {
if (m_func) {
m_func(m_ptr);
} else {
delete m_ptr;
}
}
};
Considering I'd like to handler objects of this type:
class MyClass {
public:
void describe() {
cout << "Bla bla bla ...";
}
};
Then I could use it this way:
class MyClassFunctor {
public:
void operator()(MyClass *ptr) const {
cout << "Deleting ptr using functor: ";
ptr->describe();
cout << endl;
delete ptr;
}
};
int main() {
MyClass *myclass = new MyClass();
MyClassFunctor functor();
{
Holder<MyClass> holder(myClass, functor);
}
cout << "I'm out of context now!" << endl;
}
AND (not or) this way:
void myClassDeleter(MyClass *ptr) {
cout << "Deleting ptr using function pointer: ";
ptr->describe();
cout << endl;
delete ptr;
}
int main() {
MyClass *myclass = new MyClass();
{
Holder<MyClass> holder(myClass, &myClassDeleter);
}
cout << "I'm out of context now!" << endl;
}
Notice I'd like to be able to use both approaches: Functors AND function pointers.
I'd say it is possible, since this is what Boost::shared ptr and tr1::shared_ptr does.
I tried digging into Boost::shared_ptr code, but I couldn't really understand how they do it.
I'm sorry if my code is wrong or seems to be naive. I tried to explain the problem as concisely as possible, so code correctness wasn't my main focus here (I realize this is important).
Notice I don't even think about rewriting a smart pointer class from scratch. This is out of question here, since I know it is not a wise call.
I'm interested in knowing how to do it so I can use this mechanism for other purposes. Smart pointers were simply the simplest use of that I could remember.
For now, I'd like to avoid using boost and C++11. Is it possible to do it using plain c++03?
Thanks very much for your time.
The answer is: Type Erasure.
The implementation is not that simple, and I suggest reading about Type Erasure a little (as I just did!).
First of all, you need to create the Type Erased apparatus:
class ActionBase {
public:
virtual ~ActionBase() { }
virtual bool DoIt() = 0;
};
template<typename P>
class ActionP : public ActionBase {
private:
P *ptr;
public:
ActionP(P *p) : ptr(p) { }
virtual bool DoIt() {
cout << "Standard action (nothing to do)..." << endl;
return true;
}
};
template<typename P, class A>
class ActionPA : public ActionBase {
private:
P *ptr;
A action;
public:
ActionPA(P *p, A & a ) : ptr(p), action(a) { }
virtual bool DoIt() { return action(ptr); }
};
Then you can declare the Holder class:
template<typename T>
class Holder {
private:
// Avoid object copy and assignment.
Holder(const Holder<T> &rhs);
Holder<T>& operator=(const Holder<T> &rhs);
protected:
T* ptr;
ActionBase *action;
public:
template<typename U> Holder(U *ptr) : ptr(ptr), action(new ActionP<U>(ptr)) { }
template<typename U, class A> Holder(U* p, A a) : ptr(p), action(new ActionPA<U, A>(p, a)) { }
virtual ~Holder() { delete ptr; delete action; }
bool DoAction() {
return this->action->DoIt();
}
};
Then you can use it passing function pointers, functors, or even nothing:
template<typename T>
class ActionFunctor {
public:
bool operator()(T* instance) const {
cout << "Action operator..." << endl;
// Simple operation: set the value to 3 times the original value (works for int and string!!)
instance->Set(instance->Get() + instance->Get());
return true;
}
};
template<typename T>
bool ActionFunc(T* instance) {
cout << "Action function..." << endl;
// Simple operation: set the value to 3 times the original value (works for int and string!!)
instance->Set(instance->Get() + instance->Get() + instance->Get());
return true;
}
int main() {
{
cout << "First test:" << endl;
ActionFunctor<X> actionX;
Holder<X> x1(new X(1), &ActionFunc<X>);
Holder<X> x2(new X(10), actionX);
Holder<X> x3(new X(100));
x1.DoAction();
x2.DoAction();
x3.DoAction();
}
{
cout << "Second test:" << endl;
ActionFunctor<Y> actionY;
Holder<Y> y1(new Y("A"), &ActionFunc<Y>);
Holder<Y> y2(new Y("BB"), actionY);
Holder<Y> y3(new Y("CCC"));
y1.DoAction();
y2.DoAction();
y3.DoAction();
}
return 0;
}
Here is the output:
First test:
X constructor: 1
X constructor: 10
X constructor: 100
Action function...
Action operator...
Standard action (nothing to do)...
X desstructor: 100
X desstructor: 20
X desstructor: 3
Second test:
Y constructor: "A"
Y constructor: "BB"
Y constructor: "CCC"
Action function...
Action operator...
Standard action (nothing to do)...
Y destructor: "CCC" ...
Y destructor: "BBBB" ...
Y destructor: "AAA" ...
Hope it's useful for someone else.
One obvious solution is to use boost::function or std::function. However, if you want to avoid the overhead these objects add, you can make Holder to accept a Callable as a template argument:
template <typename T, class F>
class Holder
{
private:
T *m_ptr;
F m_func;
//...
Of course, you'd have to make a helper function that would deduct the actual type of the Callable:
// depending on the nature of your functors, consider passing by const &
template<typename T, class F>
Holder<T, F> make_holder(T *t, F f)
{
return Holder<T, F>(t, f);
}
Use it like this:
auto holder = make_holder(myClass, &myClassDeleter);
// or:
auto holder = make_holder(myClass, functor);