How can one implement a method which calls another method recursively for all base classes? Conceptually:
class C {
public:
magical void recursiveWork() {
thisClass::doWork();
if (baseClassExists) {
baseClass::recursiveWork();
}
}
void doWork() {
printf("bar");
}
}
class D : public C {
public:
void doWork() {
printf("foo");
}
}
D d;
d.recursiveWork(); // prints "foobar"
You could use something to indicate the base class, like base_type below, and then recursively check if DoIt exists. (in this case I checked if base_type is different from self, in case of the most base class). Of course, it won't work with multiple inheritance (it should have something to identify all base_type's), and be careful with object slicing when going up on base classes.
#include <iostream>
#include <utility>
class A1
{
public:
using base_type = A1;
virtual ~A1(){}
virtual void DoIt(){ std::cout << "A1\n"; }
};
class A : public A1
{
public:
using base_type = A1;
virtual void DoIt(){
std::cout << "A\n";
}
};
class B : public A
{
public:
using base_type = A;
virtual void DoIt(){
std::cout << "B\n";
}
};
template<class...> using void_t = void;
template<class, class = void>
struct has_do_it : std::false_type { constexpr static bool value = false; };
template<class T>
struct has_do_it<T, void_t<decltype(std::declval<T&>().DoIt())>> : std::true_type { constexpr static bool value = true; };
template<typename T>
void DoItRec(T t)
{
if (has_do_it<T>::value) {
t.DoIt();
if(!std::is_same<T, typename T::base_type>::value)
{
typename T::base_type& base = t; // get base part (object slicing)
DoItRec(base);
}
}
}
int main()
{
B b;
DoItRec(b);
return 0;
}
Live example
Related
Is there anyway to get a type from a static base class method? For instance
class A
{
static std::type_info getClassType
{
// What do I do here
}
};
class B : public A
{
};
B instance;
auto my_type = instance::getClassType()
With C++'s lack of static variable overloading, I am having a hard time figuring out a way to determine class type across classes without doing a special virtual function in every child class which I am trying to avoid due to the sheer number.
Make a class that will be a template.
Subclass from it. Pass the child type as the template parameter.
With that, base class will know the child. The T will be the child type.
Code:
#include <iostream>
using namespace std;
template<typename T> class thebase
{
static T instance;
public:
static T& getInstance() { return instance; }
};
template <typename T> T thebase<T>::instance;
class sub1 : public thebase<sub1> {
public: void tell() { std::cout << "hello1: " << this << std::endl; }
};
class sub2 : public thebase<sub2> {
public: void tell() { std::cout << "hello2: " << this << std::endl; }
};
int main() {
sub1& ref1 = sub1::getInstance();
sub1& ref2 = sub1::getInstance();
std::cout << ((&ref1) == (&ref2)) << std::endl;
sub1::getInstance().tell();
sub2::getInstance().tell();
sub1::getInstance().tell();
sub2::getInstance().tell();
return 0;
}
Output:
1
hello1: 0x55874bff1193
hello2: 0x55874bff1192
hello1: 0x55874bff1193
hello2: 0x55874bff1192
This kind of code pattern is sometimes called CRTP
it boils down to there being a manager class that keeps track of one instance of a variety of classes and their states. You may use this singleton "instance" of these sub classes, but I want to be able to say MySubClass::instance() and then have it get the correct instance from the manager without having to write it in each sub class.
You can implement the managed classes using CRTP ("Curiously recurring template pattern") so a base class knows the derived class types and can then delegate that information to the manager class.
Try something like this:
#include <map>
#include <typeinfo>
#include <typeindex>
class Base {
public:
virtual ~Base() {}
};
class Manager
{
private:
static std::map<std::type_index, Base*> m_instances;
public:
template<typename T>
static void addInstance(Base *inst) {
if (!m_instances.insert(std::make_pair(std::type_index(typeid(T)), inst)).second)
throw ...; // only 1 instance allowed at a time!
}
template<typename T>
static void removeInstance() {
auto iter = m_instances.find(std::type_index(typeid(T)));
if (iter != m_instances.end())
m_instances.erase(iter);
}
template<typename T>
static T* getInstance() {
auto iter = m_instances.find(std::type_index(typeid(T)));
if (iter != m_instances.end())
return static_cast<T*>(iter->second);
return nullptr;
}
};
std::map<std::type_index, Base*> Manager::m_instances;
template<class Derived>
class A : public Base
{
public:
A() {
Manager::addInstance<Derived>(this);
}
~A() {
Manager::removeInstance<Derived>();
}
static Derived* getInstance() {
return Manager::getInstance<Derived>();
}
};
class B : public A<B>
{
...
};
class C : public A<C>
{
...
};
B b_inst;
C c_inst;
...
B *pB = B::getInstance();
if (pB) ...
C *pC = C::getInstance();
if (pC) ...
Live Demo
Based on your own example of code in your own answer, here's a final result working:
# include <iostream>
# include <typeinfo>
template <class T>
class A
{
public:
static const std::type_info& getClassType()
{
return typeid(T);
}
};
class B : public A<B>
{ /* ... */ };
class C : public A<C>
{ /* ... */};
class D : public A<D>
{ /* ... */};
int main()
{
B b; C c; D d;
auto& b_type = b.getClassType();
auto& c_type = c.getClassType();
auto& d_type = d.getClassType();
std::cout << b_type.name() << std::endl;
std::cout << c_type.name() << std::endl;
std::cout << d_type.name() << std::endl;
}
Output:
1B 1C 1D
Someone above mentioned the CRTP or "Curiously recurring template pattern". Using this, I have not tested it, but it appears I may be able to write:
template <class T>
class A
{
static std::type_info getClassType
{
return typeid(T);
}
};
class B : public A<B>
{
};
B instance;
auto my_type = instance::getClassType()
I'm building a c++ framework that can be extended by adding new class
I would like to find a way for simplifying the extension of new classes.
my current code look like:
class Base {
public:
virtual void doxxx() {...}
};
class X: public Base {
public:
static bool isMe(int i) { return i == 1; }
};
class Y: public Base {
public:
static bool isMe(int i) { return i == 2; }
};
class Factory {
public:
static std::unique_ptr<Base> getObject(int i) {
if (X::isMe(i)) return std::make_unique<X>();
if (Y::isMe(i)) return std::make_unique<Y>();
throw ....
}
};
Also for every new class a new if-statement must be added.
Now I would like to find a way to rewrite my Factory class (using meta programming) that adding a new class can be done by calling an add method
and the factory class looks like following pseudo code:
class Factory
{
public:
static std::unique_ptr<Base> getObject(int i) {
for X in classNames:
if (X::isMe(i)) return std::make_unique<X>();
throw ....
}
static void add() {...}
static classNames[];...
};
Factory::add(X);
Factory::add(Y);
.
.
is something like that possible?
Many thanks in advance
You might do something like the following:
template <typename ... Ts>
class Factory {
public:
static std::unique_ptr<Base> createObject(int i) {
if (i < sizeof...(Ts)) {
static const std::function<std::unique_ptr<Base>()> fs[] = {
[](){ return std::make_unique<Ts>();}...
};
return fs[i]();
}
throw std::runtime_error("Invalid arg");
}
};
Usage would be:
using MyFactory = Factory<X, Y /*, ...*/>;
auto x = MyFactory::createObject(0);
auto y = MyFactory::createObject(1);
If you want runtime registration, you might do instead:
class Factory {
public:
static std::unique_ptr<Base> createObject(int i) {
auto it = builders.find(i);
if (it == builders.end()) {
throw std::runtime_error("Invalid arg");
}
return it->second();
}
template <typename T>
void Register()
{
builders.emplace(T::Id, [](){ return std::make_unique<T>();});
}
private:
std::map<int, std::function<std::unique_ptr<Base>()>> builders;
};
Usage would be:
class X: public Base {
public:
static constexpr int id = 1;
};
class Y: public Base {
public:
static constexpr int id = 2;
};
and
Factory factory;
factory.register<X>();
factory.register<Y>();
auto x = factory.createObject(1);
auto y = factory.createObject(Y::id);
You can just have a template function:
#include <memory>
class Base {
public:
virtual void doxxx() { /* ... */ };
};
template<int i>
std::unique_ptr<Base> getObject();
#define REGISTER_CLASS(CLS, ID) \
template<> \
std::unique_ptr<Base> getObject<ID>() { return std::unique_ptr<Base>(new CLS()); }
class X1: public Base {
public:
// ...
};
REGISTER_CLASS(X1, 1)
class X2: public Base {
public:
// ...
};
REGISTER_CLASS(X2, 2)
int main()
{
auto obj1 = getObject<1>(); // Makes X1
auto obj2 = getObject<2>(); // Makes X2
return 0;
}
However this only allows for class id values known at compile time.
You could do something like this:
#include <type_traits>
#include <utility>
#include <memory>
#include <functional>
#include <stdexcept>
class I {
public:
virtual ~I(); // Always give a polymorphic class a virtual dtor!
virtual void doxxx();
};
enum class I_Key {
X = 1,
Y
/*...*/
};
struct I_Key_Order {
bool operator()(I_Key k1, I_Key k2) const
{
using U = std::underlying_type_t<I_Key>;
return static_cast<U>(k1) < static_cast<U>(k2);
}
};
class I_Factory {
public:
using Generator = std::function<std::unique_ptr<I>()>;
static std::unique_ptr<I> getObject(I_Key key) const;
static void add(I_Key key, Generator gen);
template <class T>
class AutoRegister {
public:
AutoRegister() {
auto generator = []() -> std::unique_ptr<I>
{ return std::make_unique<T>(); };
add(T::class_key, std::move(generator));
}
AutoRegister(const AutoRegister&) = delete;
AutoRegister& operator=(const AutoRegister&) = delete;
};
private:
using GenMapT = std::map<I_Key, Generator, I_Key_Order>;
static GenMapT& m_generators();
};
inline std::unique_ptr<I> I_Factory::getObject(I_Key key)
{
auto& gen_map = m_generators();
auto iter = gen_map.find(key);
if (iter != gen_map.end())
return iter->second();
throw std::invalid_argument("unknown I_Factory key");
}
inline void I_Factory::add(I_Key key, Generator gen)
{
m_generators().emplace(key, std::move(gen));
}
I_Factory::GenMapT& I_Factory::m_generators()
{
static GenMapT generators;
return generators;
}
class X : public I {
public:
static constexpr I_Key class_key = I_Key::X;
static const I_Factory::AutoRegister<X> _reg;
};
class Y : public I {
public:
static constexpr I_Key class_key = I_Key::Y;
static const I_Factory::AutoRegister<Y> _reg;
};
Note in addition to an I_Factory::add() function, I've set up a second often easier way to have a generator for class C added: define an object of type I_Factory::AutoRegister<C>, as long as C::class_key is a valid enumerator. If the object is a static class member, the adding will happen essentially at the start of the program. This will only work if the class has a public default constructor, so the add function might still be used if something different is necessary.
Here is one version with an add function and a map to store the different types.
class Base {
public:
virtual void doxxx() {...}
};
class X: public Base {
public:
static int isMe = 1;
};
class Y: public Base {
public:
static int isMe = 2;
};
class Factory {
public:
static std::unique_ptr<Base> getObject(int i) {
if (classID.find(i) != classID.end())
return classID[i]();
throw ....
}
template <typename C>
static void add() {
classID[C::isMe] = [](){ return std::make_unique<C>(); };
}
static std::map<int, std::function<std::unique_ptr<Base>()>> classID;
};
// Called like this
Factory::add<X>();
Factory::add<Y>();
A C++14 solution.
Required headers:
#include <memory>
#include <iostream>
A class to throw when the index cannot be found
class ClassNotIndexed{};
A helper class to help create a binding between the index and the requested type:
template< typename ClassType, typename IndexType, IndexType idx >
class ClassIndexer
{};
The primary template for out factory class
template <typename... >
class ClassSelector;
Base case for factory class. When index is found then create the unique_pointer, otherwise throw an exception:
template<typename BaseClass,
typename ClassType, typename IndexType, IndexType idx,
template<typename,typename,IndexType> typename T>
class ClassSelector<BaseClass, T<ClassType,IndexType, idx>>
{
public:
constexpr static
std::unique_ptr<BaseClass> getObject(IndexType i)
{
if (i == idx)
return std::make_unique<ClassType>();
else
throw ClassNotIndexed();
}
};
Variadic template which takes many Indexed classes.
If the index of the first class is a match, then make_unique_pointer otherwise check the next indexed class:
template< typename BaseClass,
typename ClassType, typename IndexType, IndexType idx,
template< typename , typename, IndexType > typename T,
typename... Ts >
class ClassSelector<BaseClass, T<ClassType,IndexType, idx>, Ts... > : ClassSelector< BaseClass, Ts ... >
{
using Base = ClassSelector< BaseClass, Ts ... >;
public:
constexpr static
std::unique_ptr<BaseClass> getObject(IndexType i)
{
if (i == idx)
return std::make_unique<ClassType>();
else
return Base::getObject( i );
}
};
Example:
class Base
{
public:
virtual void doxxx() {}
};
class X : public Base
{
public:
//static bool isMe( int i ) { return i == 1; }
void doxxx() override {std::cout << "I'm X !!\n";}
};
class Y : public Base
{
public:
//static bool isMe( int i ) { return i == 2; }
void doxxx() override {std::cout << "I'm Y !!\n";}
};
int main()
{
using Factory = ClassSelector<
Base,
ClassIndexer< X, int, 1 >,
ClassIndexer< Y, int, 2 >
>;
Factory::getObject( 1 )->doxxx();
Factory::getObject( 2 )->doxxx();
int choose;
std::cin >> choose;
Factory::getObject( choose )->doxxx();
return 0;
}
Consider
struct AbstractClass {};
struct Derived1 : AbstractClass {
using type = int;
};
struct Derived2 : AbstractClass {
using type = char;
};
struct Derived3 : AbstractClass {
using type = bool;
};
int main() {
AbstractClass* a[] = {new Derived1, new Derived2, new Derived3};
}
How to get type from a[0], a[1], a[2]?
Here is what I'm trying to accomplish. I guess there is no other way to do this than this?
#include <iostream>
struct Object { virtual ~Object() = default; };
struct A : Object {};
struct B : Object {};
struct C : Object {};
struct AbstractClass {
virtual void take (Object*) {
std::cout << "Accepted.\n";
}
};
template <typename...> struct ObjectTypes;
template <typename First, typename... Rest>
struct ObjectTypes<First, Rest...> : ObjectTypes<Rest...> {
bool operator()(Object* o) const {
if (dynamic_cast<First*>(o))
return true;
return ObjectTypes<Rest...>::operator()(o);
}
};
template <>
struct ObjectTypes<> {
bool operator()(Object*) const {return false;}
};
struct Derived1 : AbstractClass {
using type = ObjectTypes<A,B>;
virtual void take (Object* o) override {
if (type()(o)) // This is why I want to use type from AbstractClass.
return AbstractClass::take(o);
std::cout << "Rejected.\n";
}
};
struct Derived2 : AbstractClass {
using type = ObjectTypes<A,C>;
virtual void take (Object* o) override {
if (type()(o))
return AbstractClass::take(o);
std::cout << "Rejected.\n";
}
};
struct Derived3 : AbstractClass {
using type = ObjectTypes<B,C>;
virtual void take (Object* o) override {
if (type()(o))
return AbstractClass::take(o);
std::cout << "Rejected.\n";
}
};
int main() {
AbstractClass* abs[] = {new Derived1, new Derived2, new Derived3};
A* a = new A;
B* b = new B;
C* c = new C;
for (AbstractClass* x : abs) {
x->take(a);
x->take(b);
x->take(c);
std::cout << "------------\n";
}
}
Notice the repetitions in Derived1, Derived2, Derived3, etc...? Hence my original goal was to have it all done in the base class AbstractClass.
I rather thought about sth like:
#include <iostream>
struct Object { virtual ~Object() = default; };
struct A : Object {};
struct B : Object {};
struct C : Object {};
struct SuperObjectType {
public:
virtual bool operator()(Object *o) const = 0;
};
template <typename First, typename... Rest>
struct ObjectTypes: SuperObjectType {
bool operator()(Object* o) const override {
if (dynamic_cast<First*>(o))
return true;
return ObjectTypes<Rest...>()(o);
}
};
template <typename OnlyOne>
struct ObjectTypes<OnlyOne>: SuperObjectType {
bool operator()(Object* o) const override {
return dynamic_cast<OnlyOne*>(o);
}
};
struct AbstractClass {
SuperObjectType *sot;
void take (Object* o) {
if ((*sot)(o)) {
std::cout << "ACCEPTED" << std::endl;
} else {
std::cout << "REJECTED" << std::endl;
}
}
};
struct Derived1 : AbstractClass {
Derived1() {
sot = new ObjectTypes<A,B>;
}
};
struct Derived2 : AbstractClass {
Derived2() {
sot = new ObjectTypes<A,C>;
}
};
struct Derived3 : AbstractClass {
Derived3() {
sot = new ObjectTypes<B,C>;
}
};
int main() {
AbstractClass* abs[] = {new Derived1, new Derived2, new Derived3};
A* a = new A;
B* b = new B;
C* c = new C;
for (AbstractClass* x : abs) {
x->take(a);
x->take(b);
x->take(c);
std::cout << "------------\n";
}
}
But I'm happy I've inspired you ;)
Minor alternative to (perhaps) speed up the performance:
template <typename First, typename... Rest>
struct ObjectTypes: ObjectTypes<Rest...> { // Derive from ObjectTypes<Rest...> instead.
virtual bool operator()(Object* o) const override {
if (dynamic_cast<First*>(o))
return true;
return ObjectTypes<Rest...>::operator()(o);
// So now ObjectTypes<Rest...>::operator() can be used, and thus avoid instantiation.
}
};
template <typename T>
struct ObjectTypes<T>: SuperObjectType {
virtual bool operator()(Object* o) const override {
return dynamic_cast<T*>(o);
}
};
Because ObjectTypes<T> is derived from SuperObjectType for any type T, then ObjectTypes<First, Rest...> is derived from SuperObjectType as well (by being derived from ObjectTypes<Last>, were Last is the last type in Rest...). So everything still works (tested).
Solution inspired by Wojciech Frohmberg's suggestion, though I'm not sure this is what he meant. I actually don't know what he meant and I think he meant something else, and would like to see his solution and find out what he was actually saying.
#include <iostream>
struct Object { virtual ~Object() = default; };
struct A : Object {};
struct B : Object {};
struct C : Object {};
template <typename...> struct ObjectTypes;
template <typename First, typename... Rest>
struct ObjectTypes<First, Rest...> : ObjectTypes<Rest...> {
bool operator()(Object* o) const {
if (dynamic_cast<First*>(o))
return true;
return ObjectTypes<Rest...>::operator()(o);
}
};
template <>
struct ObjectTypes<> {
bool operator()(Object*) const {return false;}
};
struct AbstractClass {
virtual void take (Object*) = 0;
template <typename... Ts> void takeHelper (Object* o, ObjectTypes<Ts...>&& types) {
if (types(o)) std::cout << "Accepted.\n"; // And now do whatever with o.
else std::cout << "Rejected.\n";
}
};
template <typename Derived>
struct AbstractClassCRTP : AbstractClass {
virtual void take (Object* o) override {
takeHelper(o, typename Derived::type{});
}
};
struct Derived1 : AbstractClassCRTP<Derived1> {
using type = ObjectTypes<A,B>;
};
struct Derived2 : AbstractClassCRTP<Derived2> {
using type = ObjectTypes<A,C>;
};
struct Derived3 : AbstractClassCRTP<Derived3> {
using type = ObjectTypes<B,C>;
};
int main() {
AbstractClass* abs[] = {new Derived1, new Derived2, new Derived3};
A* a = new A;
B* b = new B;
C* c = new C;
for (AbstractClass* x : abs) {
x->take(a);
x->take(b);
x->take(c);
std::cout << "------------\n";
}
}
Output:
Accepted.
Accepted.
Rejected.
------------
Accepted.
Rejected.
Accepted.
------------
Rejected.
Accepted.
Accepted.
I try to implement the Visitor pattern with templated derived classes
I work with gcc 4.5
here is the VisitorTemplate.hpp, I specialized Derived in the class Visitor, but I'd like to be able to handle any type:
edit : thanks to the suggestions of interjay, the code compiles and runs without errors now
#ifndef VISITORTEMPLATE_HPP_
#define VISITORTEMPLATE_HPP_
#include <iostream>
#include <string>
using namespace std;
template<class T> Derived;
class Visitor
{
public:
virtual void visit(Derived<string> *e) = 0;
};
class Base
{
public:
virtual void accept(class Visitor *v) = 0;
};
template<class T>
Derived: public Base
{
public:
virtual void accept(Visitor *v)
{
v->visit(this);
}
string display(T arg)
{
string s = "This is : " + to_string(arg);
return s;
}
};
class UpVisitor: public Visitor
{
virtual void visit(Derived<string> *e)
{
cout << "do Up on " + e->display("test") << '\n';
}
};
class DownVisitor: public Visitor
{
virtual void visit(Derived<string> *e)
{
cout << "do Down on " + e->display("test") << '\n';
}
};
#endif /* VISITORTEMPLATE_HPP_ */
main.cpp
Base* base = new Derived<string>();
Visitor* up = new UpVisitor();
Visitor* down = new DownVisitor();
base->accept(up);
base->accept(down);
Now my goal is to use Derived in visit without specializing; unfortunately, visit is a virtual method so I can't template it
From Modern C++ - Design Generic Programming and Design Patterns Applied - Andrei Alexandrescu
#include <iostream>
class BaseVisitor
{
public:
virtual ~BaseVisitor() {};
};
template <class T, typename R = int>
class Visitor
{
public:
virtual R visit(T &) = 0;
};
template <typename R = int>
class BaseVisitable
{
public:
typedef R ReturnType;
virtual ~BaseVisitable() {};
virtual ReturnType accept(BaseVisitor & )
{
return ReturnType(0);
}
protected:
template <class T>
static ReturnType acceptVisitor(T &visited, BaseVisitor &visitor)
{
if (Visitor<T> *p = dynamic_cast< Visitor<T> *> (&visitor))
{
return p->visit(visited);
}
return ReturnType(-1);
}
#define VISITABLE() \
virtual ReturnType accept(BaseVisitor &v) \
{ return acceptVisitor(*this, v); }
};
/** example of use */
class Visitable1 : public BaseVisitable<int>
{
/* Visitable accept one BaseVisitor */
public:
VISITABLE();
};
class Visitable2 : public BaseVisitable<int>
{
/* Visitable accept one BaseVisitor */
public:
VISITABLE();
};
class VisitorDerived : public BaseVisitor,
public Visitor<Visitable1, int>,
public Visitor<Visitable2, int>
{
public:
int visit(Visitable1 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int visit(Visitable2 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main(int argc, char **argv)
{
VisitorDerived visitor;
Visitable1 visitable1;
Visitable2 visitable2;
visitable1.accept(visitor);
visitable2.accept(visitor);
}
Is possible to avoid dynamic_cast with CRTP pattern like:
#include <iostream>
class BaseVisitor
{
public:
virtual ~BaseVisitor() {};
};
template <class T>
class Visitor
{
public:
virtual void visit(T &) = 0;
};
template <class Visitable>
class BaseVisitable
{
public:
template <typename T>
void accept(T & visitor)
{
visitor.visit(static_cast<Visitable &>(*this));
}
};
/** example of use */
class Visitable1 : public BaseVisitable<Visitable1>
{
};
class Visitable2 : public BaseVisitable<Visitable2>
{
};
class VisitorDerived : public BaseVisitor,
public Visitor<Visitable1>,
public Visitor<Visitable2>
{
public:
void visit(Visitable1 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void visit(Visitable2 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main(int argc, char **argv)
{
VisitorDerived visitor;
Visitable1 visitable1;
Visitable2 visitable2;
visitable1.accept<VisitorDerived>(visitor);
visitable2.accept<VisitorDerived>(visitor);
}
Your Derived class cannot use Visitor because it hasn't been defined yet (it was only forward declared, and is therefore an incomplete type).
You can fix the compile error by putting the Visitor definition before Derived. You will also need to forward-declare Derived before defining Visitor:
template <class T> class Derived;
class Visitor {
public:
virtual void visit(Derived<string> *e) = 0;
};
template <class T>
class Derived : public Base {
//.... can call Visitor methods here ...
};
I have simple base and derived class that I want both have shared_from_this().
This simple solution:
class foo : public enable_shared_from_this<foo> {
void foo_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&foo::foo_do_it,shared_from_this());
}
virtual ~foo() {};
};
class bar1 : public foo , public enable_shared_from_this<bar1> {
using enable_shared_from_this<bar1>::shared_from_this;
void bar1_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar1::bar1_do_it,shared_from_this());
}
};
Causes exception tr1::bad_weak_ptr in following code:
shared_ptr<foo> ptr(shared_ptr<foo>(new bar1));
function<void()> f=ptr->get_callback();
f();
So after "googling" I have found following solution:
class bar2 : public foo {
void bar2_do_it()
{
cout<<"foo::do_it\n";
}
shared_ptr<bar2> shared_from_this()
{
return boost::static_pointer_cast<bar2>(foo::shared_from_this());
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar2::bar2_do_it,shared_from_this());
}
};
And now it works.
Is there any better and more convinient and correct way to enable_shared_from_this for both parent and child?
Thanks
The OP solution can be made more convenient by defining the following on the base class.
protected:
template <typename Derived>
std::shared_ptr<Derived> shared_from_base()
{
return std::static_pointer_cast<Derived>(shared_from_this());
}
This can be made more convenient by placing it in a base class (for reuse).
#include <memory>
template <class Base>
class enable_shared_from_base
: public std::enable_shared_from_this<Base>
{
protected:
template <class Derived>
std::shared_ptr<Derived> shared_from_base()
{
return std::static_pointer_cast<Derived>(shared_from_this());
}
};
and then deriving from it as follows.
#include <functional>
#include <iostream>
class foo : public enable_shared_from_base<foo> {
void foo_do_it()
{
std::cout << "foo::do_it\n";
}
public:
virtual std::function<void()> get_callback()
{
return std::bind(&foo::foo_do_it, shared_from_base<foo>());
}
};
class bar1 : public foo {
void bar1_do_it()
{
std::cout << "bar1::do_it\n";
}
public:
virtual std::function<void()> get_callback() override
{
return std::bind(&bar1::bar1_do_it, shared_from_base<bar1>());
}
};
Sorry, but there isn't.
The problem is that shared_ptr<foo> and shared_ptr<bar1> are different types. I don't understand everything that's going on under the hood, but I think that when the constructor returns and is assigned to a shared_ptr<foo>, the internal weak_ptr<bar1> sees that nothing is pointing to it (because only a shared_ptr<bar1> would increment the counter) and resets itself. When you call bar1::shared_from_this in get_callback, you get the exception because the internal weak_ptr isn't pointing to anything.
Essentially, enable_shared_from_this only seems to work transparently from a single class in a hierarchy. If you try implementing it manually, the problem should become obvious.
A similar solution to #evoskuil that reduces boilerplate in derived classes should you want to implement a shared_from_this() function, resulting in the following code at the point of use in the class:
auto shared_from_this() {
return shared_from(this);
}
This uses 'shim' functions outside of the class. By doing it that way it also provides a clean way to do this for classes who's interface can't be modified but derive from enable_shared_from_this - e.g.
auto shared_that = shared_from(that);
Note: Use of auto for return types here will depend upon the age of your compiler.
Shim functions that could be placed in a library header:
template <typename Base>
inline std::shared_ptr<Base>
shared_from_base(std::enable_shared_from_this<Base>* base)
{
return base->shared_from_this();
}
template <typename Base>
inline std::shared_ptr<const Base>
shared_from_base(std::enable_shared_from_this<Base> const* base)
{
return base->shared_from_this();
}
template <typename That>
inline std::shared_ptr<That>
shared_from(That* that)
{
return std::static_pointer_cast<That>(shared_from_base(that));
}
The above code relies on the fact that the type passed to shared_from(...) inherits from std::enable_shared_from_this<Base> at some point in its ancestry.
Calling shared_from_base will figure out what type that ultimately was. Since we know that That inherits from Base, a static downcast can be made.
Probably there are some pathological corner cases with classes having type conversion operators.. but that's unlikely to occur in code not designed to break this.
Example:
struct base : public std::enable_shared_from_this<base> {};
struct derived : public base
{
auto shared_from_this() {
return shared_from(this);
}
// Can also provide a version for const:
auto shared_from_this() const {
return shared_from(this);
}
// Note that it is also possible to use shared_from(...) from
// outside the class, e.g.
// auto sp = shared_from(that);
};
template <typename X>
struct derived_x : public derived
{
auto shared_from_this() {
return shared_from(this);
}
};
Compilation test:
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
auto const& const_pderived = *pderived;
const_pderived.shared_from_this();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}
https://onlinegdb.com/SJWM5CYIG
Prior solution that I posted, kept to make the comments still make sense - this placed the functions in the base class which had some problems - particularly non-uniformity between the required implementation for 'normal' classes and template classes.
Additionally the implementation in the base class would need to be repeated for new class hierarchies which is not all that DRY.
Furthermore the base class function suffered from the possibility of misuse by supplying a base class pointer from a different object. The newer scheme above avoids this entirely and the runtime assert(...) check goes.
Old implementation:
#include <cassert>
#include <memory>
class base : public std::enable_shared_from_this<base>
{
protected:
template <typename T>
std::shared_ptr<T> shared_from(T* derived) {
assert(this == derived);
return std::static_pointer_cast<T>(shared_from_this());
}
};
class derived : public base
{
public:
auto shared_from_this() {
return shared_from(this);
}
};
template <typename X>
class derived_x : public derived
{
public:
auto shared_from_this() {
return this->template shared_from(this);
}
};
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}
Quite easy; inherit public shared_from_this only in your base class. Implement an accessor in your derived class that casts to the appropriate type;
std::shared_ptr<Derived> shared()
{
return std::dynamic_pointer_cast<Derived>(Base::shared_from_this());
}
With c++23 deducing this, things become much easier. https://godbolt.org/z/j499WK58Y
#include <memory>
#include <iostream>
#include <functional>
using namespace std;
struct new_enable_shared_from_this :
public std::enable_shared_from_this<new_enable_shared_from_this> {
template <typename Self>
auto new_shared_from_this(this Self& self) {
return std::static_pointer_cast<Self>(self.shared_from_this());
}
};
class foo : public new_enable_shared_from_this {
void foo_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return bind(&foo::foo_do_it,new_shared_from_this());
}
virtual ~foo() {};
};
class bar1 : public foo {
void bar1_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return bind(&bar1::bar1_do_it,new_shared_from_this());
}
};
int main() {
auto pf = std::make_shared<foo>();
pf->get_callback()();
auto pb = std::make_shared<bar1>();
pb->get_callback()();
}
This is the previous answer:
Well, I don't like virtual function. Virtual function is just for type erasing, but we don't need type erasing all the time. So, provide a mechanism for type erasing is enough. Here is an example that don't use virtual function:
#include <iostream>
#include <functional>
#include <memory>
using namespace std;
template<typename derived>
class foo_imp {
void foo_do_it()
{
cout<<"foo::do_it\n";
}
public:
function<void()> get_callback()
{
auto&& d = static_cast<derived&>(*this);
return bind(&foo_imp::foo_do_it, d.shared_from_this());
}
};
template<typename derived>
class bar_imp {
void bar_do_it()
{
cout<<"bar::do_it\n";
}
public:
function<void()> get_callback()
{
auto&& d = static_cast<derived&>(*this);
return bind(&bar_imp::bar_do_it, d.shared_from_this());
}
};
struct foo : public foo_imp<foo>, public enable_shared_from_this<foo> {};
struct bar : public bar_imp<bar>, public enable_shared_from_this<bar> {};
struct v_foo {
virtual function<void()> get_callback() = 0;
};
template <typename T>
std::shared_ptr<v_foo> convert(const std::shared_ptr<T>& st) {
struct _ : public v_foo {
_(const std::shared_ptr<T>& st) : _st{st} {}
function<void()> get_callback() override {
return _st->get_callback();
}
std::shared_ptr<T> _st;
};
return std::make_shared<_>(st);
}
int main() {
auto sf = make_shared<bar>();
sf->get_callback()();
auto svf = convert(sf);
svf->get_callback()();
auto sb = make_shared<foo>();
sb->get_callback()();
auto svb = convert(sb);
svb->get_callback()();
}
#include <memory>
template<class T>
class Base : public std::enable_shared_from_this<T> {
};
class Derived : public Base<Derived> {
std::shared_ptr<Derived> getDerived() { return shared_from_this(); }
};