I recently had a thought of implementing virtual functions without virtual tables or storing a pointer with CRTP (though using static_cast<CRTP&>(*this) instead.
The initial set up is rather cumbersome compared to conventional virtual functions.
So the code is:
namespace detail
{
template<typename T, typename = void>
struct virtual_set_up
{
void operator()(T &) {}
};
template<typename T>
struct virtual_set_up<T, std::void_t<decltype(std::declval<T>().set_up())>>
{
void operator()(T &t) { t.set_up(); }
};
}
template<typename CRTP>
class base
{
public:
base() {}
void set_up() { detail::virtual_set_up<CRTP>()(static_cast<CRTP &>(*this)); }
protected:
~base() = default;
};
class settable : public base<settable>
{
public:
void set_up() { std::cout << "settable: set_up overridden" << std::endl; }
};
class dummy : public base<dummy>
{
public:
};
int main(int, char **)
{
settable s;
dummy d;
base<settable>& baseS = s;
base<dummy>& baseD = d;
baseS.set_up();
baseD.set_up();
return 0;
}
However there is a problem: virtual_set_up<dummy> resolves to the specialization of T with declared T::set_up causing a SEGFAULT upon execution. It happens because dummy is publicly inheriting from base, which does have a set_up method.
Given that the previous problem is solvable, does this add any efficiency over having a conventional virtual function?
To solve your infinite recursion, you might still compare that "&dummy::setup != &base<dummy>::setup":
namespace detail
{
template <typename B, typename T, typename = void>
struct virtual_set_up
{
void operator()(T&) {}
};
template <typename B, typename T>
struct virtual_set_up<B, T,
std::enable_if_t<!std::is_same_v<decltype(&B::set_up),
decltype(&T::set_up)>>>
{
void operator()(T& t) { t.set_up(); }
};
}
template <typename CRTP>
class base
{
public:
base() {}
void set_up() { detail::virtual_set_up<base, CRTP>()(static_cast<CRTP &>(*this)); }
protected:
~base() = default;
};
Demo
But simpler would be to rename/split the one in base<CRTP>
template <typename CRTP>
class base
{
public:
base() {}
void set_up() { static_cast<CRTP &>(*this).set_up_v(); }
void set_up_v() { std::cout << "base\n"; }
protected:
~base() = default;
};
class settable : public base<settable>
{
public:
void set_up_v() { std::cout << "settable: set_up overridden" << std::endl; }
};
Demo
Does this add any efficiency over having a conventional virtual function?
All code there are resolve at compilation, there are no dynamic dispatch, so no overhead of virtual dispatch...
But you have nothing which is polymorphic neither here: base<dummy> and base<settable> are unrelated classes (you cannot have std::vector<base> to store then together). So comparison is unfair.
For case where all types are known at compile-time, compilers might use devirtualization optimization and remove the overhead of virtual call too.
Related
I'd like to implement a fully generic Visitor pattern using >= C++14 using template metaprogramming. I've already found a nice way to generalize the Visitor itself, but I'm having trouble defining the Visitables. The code below works, but I'd like the commented out code in main to work as well; in particular, I want to be able to have a collection of Visitables and apply a Visitor to each element.
Is what I'm trying to do even possible in C++?
Things I've tried:
class X : public Visitable<X>
This solves the problem of not having a suitable accept method in
X, but results in ambiguities X/A and X/B which the compiler
cannot resolve.
empty accept method in X without inheriting; works, but the
specialized accept methods in A and B are never called.
replace template class Visitor with regular class with function
template visit for arbitrary types; does not really change the
semantics, but is less readable IMHO
#include <iostream>
#include <vector>
template <typename I>
class Visitable {
public:
template <typename Visitor>
void accept(Visitor&& v) const {
v.visit(static_cast<const I&>(*this));
}
};
template <typename T, typename... Ts>
class Visitor : public Visitor<Ts...> {
public:
virtual void visit(const T& t);
};
template<typename T>
class Visitor<T> {
public:
virtual void visit(const T& t);
};
struct X {
// template <typename V> void accept(V&& v) const {};
};
struct A : public X, public Visitable<A> {};
struct B : public X, public Visitable<B> {};
class MyVisitor : public Visitor<A, B> {
public:
void visit(const A& a) override { std::cout << "Visiting A" << std::endl; }
void visit(const B& b) override { std::cout << "Visiting B" << std::endl; }
};
int main() {
MyVisitor v {};
// std::vector<X> elems { A(), B() };
// for (const auto& x : elems) {
// x.accept(v);
// }
A().accept(v);
B().accept(v);
}
There are a few issues with your current solution:
You don't have a polymorphic type that can represent any visitable type. This means that you don't have a way to properly store all your A and B values in a collection such that you can visit every element in the collection. X doesn't accomplish this because there is no way to require that a subclass of X also subclasses an instantiation of the Visitable class template.
You have no way of handling a mismatch of visitor/visitable types; you cannot guarantee that all values in your collection are visitable by some visitor type, without simply making the collection a vector<A> or vector<B>, in which case you lose the ability to store values of different visitable types in the same collection. You either need a way to handle at runtime the scenario of a visitor/visitable mismatch, or you need a much more complex template structure.
You cannot store polymorphic values directly in a collection. This is because vector stores its elements consecutively in memory, and therefore must assume a certain constant size for each element; by their nature polymorphic values have an unknown size. The solution is to use a collection of (smart) pointers to refer to polymorphic values elsewhere on the heap.
Here's a working adaptation of your original code:
#include <iostream>
#include <vector>
#include <memory>
template<typename T>
class Visitor;
class VisitorBase {
public:
virtual ~VisitorBase() {}
};
class VisitableBase {
public:
virtual void accept(VisitorBase& v) const = 0;
virtual ~VisitableBase() {}
};
template <typename I>
class Visitable : public VisitableBase {
public:
virtual void accept(VisitorBase& v) const {
auto visitor = dynamic_cast<Visitor<I> *>(&v);
if (visitor == nullptr) {
// TODO: handle invalid visitor type here
} else {
visitor->visit(dynamic_cast<const I &>(*this));
}
}
};
template<typename T>
class Visitor : public virtual VisitorBase {
public:
virtual void visit(const T& t) = 0;
};
struct A : public Visitable<A> {};
struct B : public Visitable<B> {};
class MyVisitor : public Visitor<A>, public Visitor<B> {
public:
void visit(const A& a) override { std::cout << "Visiting A" << std::endl; }
void visit(const B& b) override { std::cout << "Visiting B" << std::endl; }
};
int main() {
MyVisitor v {};
std::vector<std::shared_ptr<VisitableBase>> elems {
std::dynamic_pointer_cast<VisitableBase>(std::make_shared<A>()),
std::dynamic_pointer_cast<VisitableBase>(std::make_shared<B>())
};
for (const auto& x : elems) {
x->accept(v);
}
A().accept(v);
B().accept(v);
}
struct empty_t{};
template <class I, class B=empty_t>
class Visitable:public B {
public:
// ...
struct X : Visitable<X>{
};
struct A : Visitable<A,X> {};
struct B : Visitable<B,X> {};
Note however that dispatch here is static. And your vector contains Xs not As or Bs.
You probably want
template <class Visitor>
struct IVisitable {
virtual void accept(Visitor const& v) const = 0;
protected:
~IVisitable(){}
};
template <class I, class Visitor, class B=IVisitable<Visitor>>
struct Visitable {
virtual void accept(Visitor const& v) const override {
v.visit(static_cast<const I&>(*this));
}
};
which gets closer.
struct A; struct B; struct X;
struct X:Visitable<X, Visitor<A,B,X>> {
};
struct A :Visitable<A, Visitor<A,B,X>, X> {};
struct B :Visitable<B, Visitor<A,B,X>, X> {};
this still doesn't do what you want, because you have a vector of values. And polymorphic values require more work.
Make it a vector of unique ptrs to X, and add virtual ~X(){} and some * and make_uniques and this will do what you want.
Consider the below code, EventGeneratorBase is a helper class intended to provide the actual implementation for AddEventHandler() and I would like to use that implementation in the class RemoteControl instead of explicity defining it. I know it's not possible to instantiate RemoteControl without defining the method but is there a shortcut or an easy way to avoid manually defining the methods.
Note: The code in it's present form doesn't compile because RemoteControl can't be instantiated.
#include <iostream>
#include <vector>
#include <memory>
template<class TEventHandler> struct IEventGenerator {
virtual ~IEventGenerator() = default;
virtual void AddEventHandler(std::weak_ptr<TEventHandler> eventHandler) = 0;
};
template <class TEvents> struct EventGeneratorBase : IEventGenerator<TEvents> {
void AddEventHandler(std::weak_ptr<TEvents> target) {
_eventHandlers.push_back(target);
}
std::vector<std::weak_ptr<TEvents>> GetEventHandlers() {
return _eventHandlers;
}
private:
std::vector<std::weak_ptr<TEvents>> _eventHandlers;
};
struct IControlEvents {
virtual ~IControlEvents() = default;
virtual void PowerOn() = 0;
virtual void PowerOff() = 0;
};
struct IRemoteControl : IEventGenerator<IControlEvents> {
virtual ~IRemoteControl() = default;
virtual void Toggle() = 0;
};
struct RemoteControl : IRemoteControl, EventGeneratorBase<IControlEvents> {
// I don't want to define AddEventHandler() in this class and
// would like to inherit the implementation from EventGeneratorBase
void Toggle() {
for (auto tref : GetEventHandlers()) {
auto t = tref.lock();
if (t) {
t->PowerOn();
t->PowerOff();
}
}
}
};
struct Light : IControlEvents {
Light(std::string color) : _color(color) { }
void PowerOn() {
std::cout << _color << "::Light ON!" << std::endl;
}
void PowerOff() {
std::cout << _color << "::Light OFF!" << std::endl;
}
private:
std::string _color;
};
int main() {
std::shared_ptr<IRemoteControl> remote(new RemoteControl); // ERROR: Can't instantiate
std::shared_ptr<IControlEvents> light1(new Light("GREEN"));
std::shared_ptr<IControlEvents> light2(new Light("RED"));
remote->AddEventHandler(light1);
remote->AddEventHandler(light2);
remote->Toggle();
return 0;
}
Your problem is that you have two distinct sub-objects of type IEventGenerator<IControlEvents> within your RemoteControl object. One via EventGeneratorBase<IControlEvents> and one via IRemoteControl.
There are two ways to prevent you from having two distinct subobjects. The first is to inherit virtually from IEventGenerator<TEventHandler> in both spots. This has a modest run-time cost. Simply add virtual before every case of inheritance from IEventGenerator<?> and you are done.
A second method is to note that EventGeneratorBase is intended to help with implementing IEventGenerator.
template<class T> struct tag{using type=T;};
template<class Tag> using type_t=typename Tag::type;
template<class TEventHandler>
tag<TEventHandler> get_event_handler_type(
IEventGenerator<TEventHandler> const*
) { return {}; }
template<class X>
using event_handler_type = type_t< decltype( get_event_handler_type( (X*)nullptr ) ) >;
template <class Base, class TEvents = event_handler_type<Base>>
struct EventGeneratorHelper :
Base
{
void AddEventHandler(std::weak_ptr<TEvents> target) override {
_eventHandlers.push_back(target);
}
std::vector<std::weak_ptr<TEvents>> GetEventHandlers() {
return _eventHandlers;
}
private:
std::vector<std::weak_ptr<TEvents>> _eventHandlers;
};
now, go down to here:
struct RemoteControl :
EventGeneratorHelper<IRemoteControl>
{
and change how we inherit. We now interpose EventGeneratorHelper between us and IRemoteControl, so they now share the same common IEventGenerator.
This removes the need for virtual inheritance, but does up your compile time, and can cause some executable code bloat.
We can go a step further. Add this to EventGeneratorHelper:
template<class Action>
void FireEvents( Action&& action ) const {
for (auto tref : GetEventHandlers()) {
auto t = tref.lock();
if (t) {
action(t);
}
}
}
which reduces RemoteControl to:
struct RemoteControl :
EventGeneratorHelper<IRemoteControl>
{
void Toggle() {
this->FireEvents([](std::shared_ptr<IRemoteControl> const& ptr){
t->PowerOn();
t->PowerOff();
});
}
};
which I think is nice -- requiring clients to know the right way of iterating seems silly.
You have a problem in your inheritance hierarchy.
template <class TEvents> struct EventGeneratorBase :IEventGenerator<TEvents> {
[...]
};
struct IRemoteControl : IEventGenerator<IControlEvents> {
[...]
};
struct RemoteControl : IRemoteControl, EventGeneratorBase<IControlEvents> {
[...]
};
This is not doing what you might expect. Instead, your class RemoteControl inherits twice from IEventGenerator, once from IRemoteControl and once from EventGeneratorBase.
Would it be possible to disable the Foo() override in the derived class (by means of std::enable_if or some boost magic), in case T is not of a certain type, without having to write a template specialization for class Derived?
Bonus points: could the override be disabled if T does not define a certain method?
Here is my SSCCE:
#include <iostream>
#include <string>
class Base
{
public:
virtual std::string Foo()
{
return "Base";
}
};
template <typename T>
class Derived : public Base
{
public:
virtual std::string Foo() override
{
return "Derived";
}
};
int main()
{
Derived<int> testInt;
std::cout << testInt.Foo() << std::endl;
Derived<float> testFloat;
std::cout << testFloat.Foo() << std::endl;//I would like this to print 'Base'
}
UPDATE:
Thank you for the wonderful solutions, but I wasn't able to adapt them to my real code. The following example should provide a better idea of what I'm trying to achieve:
#include <iostream>
#include <string>
class Object
{
public:
void Test()
{
std::cout << "Test" << std::endl;
}
};
class EmptyObject
{
};
class Base
{
public:
virtual std::string Foo()
{
return "Base";
}
};
template <typename T>
class Derived : public Base
{
public:
virtual std::string Foo() override
{
m_object.Test();
return "Derived";
}
private:
T m_object;
};
int main()
{
Derived<Object> testObject;
std::cout << testObject.Foo() << std::endl;
Derived<EmptyObject> testEmpty;
std::cout << testEmpty.Foo() << std::endl;
}
I would do this by creating two functions that Derived::Foo can delegate to conditionally based on whether T = float. One would contain the real Derived::Foo implementation, while the other would call Base::Foo.
template <typename T>
class Derived : public Base
{
public:
virtual std::string Foo() override
{
return do_Foo(std::is_same<T, float>{});
}
private:
std::string do_Foo(std::false_type)
{
return "Derived";
}
std::string do_Foo(std::true_type)
{
return Base::Foo();
}
};
Live demo
It seems what you actually want to do is call the Derived<T>::Foo() implementation only if T defines a certain member function, otherwise Base::Foo() should be called. This can be done using expression SFINAE.
template <typename T>
class Derived : public Base
{
public:
std::string Foo() override
{
return do_Foo(true);
}
private:
template<typename U = T>
auto do_Foo(bool)
-> decltype(std::declval<U>().test(), void(), std::string())
{
return "Derived";
}
std::string do_Foo(int)
{
return Base::Foo();
}
};
Live demo
In the code above, if the type T does not define a member function named test(), the do_Foo(bool) member function template will not be viable. On the other hand, if T::test() does exist, then do_Foo(bool) will be selected because the boolean value being passed to do_Foo by Foo makes it a better match as compared to do_Foo(int).
A detailed explanation of what's going on within the decltype expression in the trailing return type can be found here.
Instead of template specialize the class, you may template specialize the method directly: (https://ideone.com/gYwt5r)
template<> std::string Derived<float>::Foo() { return Base::Foo(); }
And I only see template specialization of a class to disable future override depending of T by adding final to the virtual method.
If you need to restrict a certain type at compile time, you can use std::enable_if together with std::is_same :
typename std::enable_if<std::is_same<T, float>::value, std::string>::type
virtual Foo() override
{
return "Derived";
}
Or you can easily redirect the call to the Base method if the template type is not the type you are looking for, still with std::is_same :
virtual std::string Foo() override
{
return std::is_same<T, float>::value ? Base::Foo() : "Derived";
}
As for the Bonus, you can get the trait from this SO answer, adapted here with decltype, for a method bar() :
template <typename T>
class has_bar
{
typedef char one;
typedef long two;
template <typename C> static one test(decltype(&C::bar) ) ;
template <typename C> static two test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
The limitation is that you can't put constraints on the arguments or return types.
virtual std::string Foo() override
{
return has_bar<T>::value ? "Derived" : Base::Foo() ;
}
Note:
You could also use has_bar together with enable_if as in my first example, to disable it a compile time.
You can add an intermediate class to your hierarchy:
class Base
{
public:
virtual std::string Foo()
{
return "Base";
}
};
template <typename T>
class Intermediate : public Base
{
// common operations with m_object
protected: // not private!
T m_object;
};
template <typename T, typename = bool>
class Derived : public Intermediate<T> {};
template <typename T>
class Derived<T, decltype(std::declval<T>().Test(), void(), true)>
: public Intermediate<T>
{
public:
virtual std::string Foo() override
{
this->m_object.Test(); // this-> is necessary here!
return "Derived";
}
};
The full example compiles successfully with both clang 3.4 and g++ 4.8.2.
I'm trying to figure out a way to dynamically cast an instance of a child class to its parent in a somewhat difficult set of conditions.
Specifically, I have a an object hierarchy that looks something like (I've simplified a lot, so if something doesn't make sense, it might be due to the simplification):
class Object {
public:
virtual ~Object() {}
};
// shown just to give an idea of how Object is used
class IntObject: public Object {
protected:
int value;
public:
IntObject(int v) { value = v; }
int getValue() { return value; }
};
template <class T>
class ObjectProxy: public Object {
protected:
T *instance;
public:
ObjectProxy(T *instance): instance(instance) {}
T *getInstance() { return instance; }
};
The ObjectProxy class essentially acts as a wrapper to allow other types to be used in the Object hierarchy. Specifically, it allows pointers to class instances to be kept, and used later when invoking the instance's methods. For example, suppose I have:
class Parent {
protected:
int a;
public:
Parent(int v) { a = v; }
virtual ~Parent() {}
void setA(int v) { a = v; }
int getA() { return a; }
};
class Child: public Parent {
protected:
int b;
public:
Child(int v1, int v2): Parent(v1) { b = v2; }
void setA(int v) { b = v; }
int getB() { return b; }
};
I might use them in the following situation:
template <typename C>
void callFn(std::list<Object *> &stack, std::function<void (C*)> fn) {
Object *value = stack.front();
stack.pop_front();
ObjectProxy<C> *proxy = dynamic_cast<ObjectProxy<C> *>(value);
if (proxy == nullptr) {
throw std::runtime_error("dynamic cast failed");
}
fn(proxy->getInstance());
}
void doSomething(Parent *parent) {
std::cout << "got: " << parent->getA() << std::endl;
}
int main() {
std::list<Object *> stack;
// this works
stack.push_back(new ObjectProxy<Child>(new Child(1, 2)));
callFn<Child>(stack, doSomething);
// this will fail (can't dynamically cast ObjectProxy<Child> to ObjectProxy<Parent>)
stack.push_back(new ObjectProxy<Child>(new Child(1, 2)));
callFn<Parent>(stack, doSomething);
}
As noted in the above comments, this code fails for a known reason. In the sample code, it's easy to avoid invoking callFn<Parent>(stack, doSomething). However, in my real code, I am using the signature of the function to determine type, and if its a method for the parent class, that will automatically be used for the template parameter.
My question is if there is any way to achieve the dynamic cast from ObjectProxy from an object of type of ObjectProxy. Part of the complication comes from the fact that in the function callFn, you only have the Parent type and not the child type.
I looked into using type-erasure via boost::any (i.e. ObjectProxy stops being templated, and instead has boost::any instance), but still ran into problems when it came to dynamic-casting (boost::any_cast is static). I did find mention to a dynamic_any on SO, but have not gotten it to work properly yet.
Any help or insight into the problem is greatly appreciated.
The dynamic cast is failing because the classes that are instantiations of ObjectProxy do not share the same hierarchy as the types given in the parameterisation of ObjectProxy. I see two approaches that may help. One, you make the types given to ObjectProxy share a single common base class and move the dynamic cast away from ObjectProxy and onto the instances.
namespace approach2 {
struct object_t {
virtual ~object_t() { }
};
struct required_base_t {
virtual ~required_base_t() { }
};
class object_proxy_base_t : public object_t {
required_base_t* instance_;
public:
object_proxy_base_t(required_base_t* i) : instance_ (i) { }
template <class T>
T* cast_to() const
{
return dynamic_cast<T*>(instance_);
}
};
template <class value_t>
class object_proxy_t : public object_proxy_base_t {
value_t* instance_;
public:
object_proxy_t(value_t* i)
: object_proxy_base_t (i),
instance_ (i)
{
}
};
template <class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_t<value_t>(new value_t(value));
}
struct parent_t : required_base_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy(parent_t());
object_t* b = new_with_proxy(child_t());
std::cout
<< dynamic_cast<object_proxy_base_t*>(a)->cast_to<parent_t>() << '\n' // works
<< dynamic_cast<object_proxy_base_t*>(b)->cast_to<parent_t>() << '\n' // works
;
}
}
This approach is not possible if you cannot change the base classes of all types used by ObjectProxy. Which leads to the second solution where you make ObjectProxy instantiations have the same hierarchy as the types used to parameterise it.
namespace approach3 {
struct object_t {
virtual ~object_t() { }
};
struct empty_t {
template <class T>
empty_t(T*) { }
};
template <class value_t>
class object_proxy_t : public virtual object_t {
value_t* instance_;
public:
object_proxy_t(value_t* i) : instance_ (i) { }
};
template <class value_t, class base_t>
class object_proxy_sub_t :
public object_proxy_t<value_t>,
public base_t {
public:
object_proxy_sub_t(value_t* i)
: object_proxy_t<value_t>(i),
base_t (i)
{
}
};
template <class base_t, class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_sub_t<value_t, base_t>(new value_t(value));
}
struct parent_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy<empty_t>(parent_t());
object_t* b = new_with_proxy<object_proxy_t<parent_t> >(child_t());
std::cout
<< dynamic_cast<object_proxy_t<parent_t>*>(a) << '\n' // works
<< dynamic_cast<object_proxy_t<parent_t>*>(b) << '\n' // works
;
}
}
This approach places fewer requirements on the types involved but means more work to keep the hierarchies in sync.
Building off of Bowie Owen's first answer, I realized that while the types given would likely not be derived from the same class (it's a library), I could force that to occur:
struct ObjectProxyBaseType {
virtual ~ObjectProxyBaseType() {}
};
template <class T>
class ObjectProxyType: public ObjectProxyBaseType, public T {
public:
// allow construction via parameters
template <typename... Args>
ObjectProxyType(Args &&... args): T(std::move(args)...) {}
// or construction via copy constructor
ObjectProxyType(T *t): T(*t) {}
virtual ~ObjectProxyType() {}
};
Thus, if I have class Child, I can create an instance of ObjectProxyType<Child>, which causes it to also inherit ObjectProxyBaseType. The rest of the code follows Bowie's suggestion:
class ObjectProxy: public Object {
protected:
ObjectProxyBaseType *instance;
public:
template <typename T>
ObjectProxy(ObjectProxyType<T> *i) {
instance = i;
}
template <typename T>
ObjectProxy(T *value) {
instance = new ObjectProxyType<T>(value);
}
template <typename T>
T *castTo() const {
return dynamic_cast<T *>(instance);
}
};
And an example of code that works:
int main() {
std::list<Object *> stack;
stack.push_back(new ObjectProxy(new Child(1, 2)));
callFn<Child>(stack, doSomething);
stack.push_back(new ObjectProxy(new Child(5, 6)));
callFn<Parent>(stack, doSomething);
}
I've had to do something somewhat similar recently. I've used an approach which worked for me, but might not be appropriate in this case; use your discretion. This hinges on the fact that you (or the person extending this code, if any) have full knowledge of what hierarchies will be used as template parameters.
So let's say these hierarchies are the following:
class Parent1
class Child1: public Parent1
class Child11: public Child1
...
class Parent2
class Child2: public Parent2
...
Then you build a holder class. It is a bit complicated for a simple reason - my compiler doesn't support default template parameters on functions, so I am using helper structs to enable SFINAE.
This class needs to be able to hold objects belonging to all hierarchies (through a base class pointer).
class TypeHolder
{
template<class T, class E=void>
struct GetHelper
{
static T* Get(const TypeHolder* th) { return nullptr; }
//you can actually add code here to deal with non-polymorphic types through this class as well, if desirable
};
template<class T>
struct GetHelper<T, typename std::enable_if<std::is_polymorphic<T>::value, void>::type>
{
static T* Get(const TypeHolder* th)
{
switch(th->type)
{
case P1: return dynamic_cast<T*>(th->data.p1);
case P2: return dynamic_cast<T*>(th->data.p2);
//and so on...
default: return nullptr;
}
}
};
template<class T, class E=void>
struct SetHelper
{
static void Set(T*, TypeHolder* th) { th->type = EMPTY; }
};
template<class T>
struct SetHelper<T, typename std::enable_if<std::is_polymorphic<T>::value, void>::type>
{
static void Set(T* t, TypeHolder* th)
{
th->data.p1 = dynamic_cast<Parent1*>(t);
if(th->data.p1) { th->type = P1; return; }
th->data.p2 = dynamic_cast<Parent2*>(t);
if(th->data.p2) { th->type = P2; return; }
//...and so on
th->type = EMPTY;
}
};
public:
TypeHolder(): type(EMPTY) { }
template<class T>
T* GetInstance() const
{
return GetHelper<T>::Get(this);
}
template<class T>
void SetInstance(T* t)
{
SetHelper<T>::Set(t, this);
}
private:
union
{
Parent1* p1;
Parent2* p2;
//...and so on
} data;
enum
{
EMPTY,
P1,
P2
//...and so on
} type;
};
By the way, the reason we need the SFINAE trick is because of the dynamic_casts, which will not compile on non-polymorphic types.
Now all you need to do is modify your classes just a little bit :)
class ObjectProxyBase
{
public:
virtual const TypeHolder& GetTypeHolder() const = 0;
};
template<class T>
class ObjectProxy: public Object, public ObjectProxyBase
{
T* instance;
static TypeHolder th; //or you can store this somewhere else, or make it a normal (but probably mutable) member
public:
ObjectProxy(T* t): instance(t) { }
T* getInstance() const { return instance; }
const TypeHolder& GetTypeHolder() const { th.SetInstance(instance); return th; }
//... and the rest of the class
};
template<class T>
TypeHolder ObjectProxy<T>::th;
I hope this code is actually correct, since I mostly typed it into the browser window (mine used different names).
And now for the final piece: the function.
template <typename C>
void callFn(std::list<Object *> &stack, std::function<void (C*)> fn) {
Object *value = stack.front();
stack.pop_front();
ObjectProxyBase *proxy = dynamic_cast<ObjectProxyBase *>(value);
if (proxy == nullptr) {
throw std::runtime_error("dynamic cast failed");
}
C* heldobj = proxy->GetTypeHolder().GetInstance<C>(); //I used to have a dynamic_cast here but it was unnecessary
if (heldobj == nullptr) {
throw std::runtime_error("object type mismatch");
}
fn(heldobj);
}
You only need to use this approach for hierarchies, and can still use the dynamic_cast directly to ObjectProxy<C>* in other cases (essentially, you'll want to try both and see if one succeeds).
I hope this is at least a little bit helpful.
I've two classes:
struct A {
template <typename T>
void print(T& t){
// do sth specific for A
}
};
struct B : A {
template <typename T>
void print(T& t){
// do sth specific for B
}
};
In such case, the more general Base class with virtual functions (which A and B both inherit from) cannot be compiled, since there is no virtual for template. As I try to delegate generally all A or B objects under same "interface", does anyone has the idea to resolve such problem? Thank you in advance.
Sincerely,
Jun
You can think about using using CRTP.
template<typename Derived>
struct Base {
template <typename T>
void print(T& t){
static_cast<Derived*>(this)->print(t);
}
};
struct A : Base<A> {
// template print
};
struct B : Base<B> {
// template print
};
Example Usage:
template<typename T, typename ARG>
void foo (Base<T>* p, ARG &a)
{
p->print(a);
}
This method will be called as,
foo(pA, i); // pA is A*, i is int
foo(pB, d); // pB is B*, d is double
Here is another demo code.
Using a proxy class to get B's method
class A {
public:
friend class CProxyB;
virtual CProxyB* GetCProxyB() = 0;
};
class B;
class CProxyB
{
public:
CProxyB(B* b){mb = b;}
template <typename T>
void printB(T& t)
{
mb->print(t);
}
B* mb;
};
class B:public A {
public:
virtual CProxyB* GetCProxyB(){return new CProxyB(this);};
template <typename T>
void print(T& t){
printf("OK!!!!!\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* a = new B;
CProxyB* pb = a->GetCProxyB();
int t = 0;
pb->printB(t);
return 0;
}
Two options:
Option one: Virtualize the method where if the user does not provide an implementation, the Base class' is used.
template <typename T>
struct A {
virtual void print(T& t);
};
template <typename T>
void A::print(T& t) {
// do sth specific for A
}
template <typename T>
struct B : A {
virtual void print(T& t);
};
void B::print(T& t) {
// do sth specific for B
}
Option two: Abstract the method where if the user does not provide an implementation, the code will not compile.
template <typename T>
struct A {
virtual void print(T& t)=0;
};
template <typename T>
struct B : A {
virtual void print(T& t){
// do sth specific for B
}
};
template <typename T>
void B::print(T& t){
// do sth specific for B
}
Other than the above mentioned, if you do not make them virtual, the Derived class will Shadow the Base class method and that is most certainly not what you intended. Hence, impossible.
my question is how to use single pointer to different A or B objects.
You can do this without virtual functions per-se. But all you will really be doing is writing an implementation of a V-table and virtual functions.
If I were going to manually implement virtual functions, I would base it all on a Boost.Variant object. The variant would effectively hold the member data for each class. To call a function, you use a variant visitor functor. Each "virtual function" would have its own visitor functor, which would have different overloads of operator() for each of the possible types within the variant.
So you might have this:
typedef boost::variant<StructA, StructB, StructC> VirtualClass;
You could store any one of those objects in the variant. You would call a "virtual function" on the object like this:
VirtualClass someObject(StructA());
boost::apply_visitor(FunctorA(), someObject);
The class FunctorA is your virtual function implementation. It is a visitor, defined like this:
class FunctorA : public boost::static_visitor<>
{
void operator()(StructA &arg){
//Do something for StructA
}
void operator()(StructB &arg){
//Do something for StructB
}
void operator()(StructC &arg){
//Do something for StructC
}
}
Visitors can have return values, which are returned by apply_visitor. They can take arguments, by storing the arguments as members of the visitor class. And so forth.
Best of all, if you ever change your variant type, to add new "derived classes", you will get compiler errors for any functors that don't have overloads for the new types.
But to be honest, you should just be using virtual functions.
By using CRTP(Curiously recurring template pattern), you can achieve static polymorphsim without virtual.
#include <iostream>
using namespace std;
#define MSG(msg) cout << msg << endl;
template<class Derived>
class Base{
public:
void print()
{
static_cast<Derived*>(this)->print();
}
};
class Derived1 : public Base<Derived1>
{
public:
void print()
{
MSG("Derived 1::print");
}
};
class Derived2 : public Base<Derived2>
{
public:
void print()
{
MSG("Derived 2::print");
}
};
template<class T>
void callme(Base<T>& p)
{
p.print();
}
int main()
{
Base<Derived1> p1;
Base<Derived2> p2;
callme(p1);
callme(p2);
system("pause");
return 0;
}
//Result :
//Derived 1::print
//Derived 2::print