Is there a way to prevent shared_from_this() call for a stack-allocated object ?
The enable_shared_from_this<> in the base classes list is a strong indicator for class user, but is there a way to enforce the correct usage ?
Example code:
class C : public enable_shared_from_this<C>
{
public:
shared_ptr<C> method() { return shared_from_this(); }
};
void func()
{
C c;
shared_ptr<C> ptr = c.method(); // exception coming from shared_from_this()
}
So to protect against this problem you can make your constructors private and only provide creation functions that return shared_ptr - this way the object can't be allocated on the stack, like this:
class C : public enable_shared_from_this<C>
{
public:
static shared_ptr<C> create() { return shared_ptr<C>(new C() ); }
shared_ptr<C> method() { shared_from_this(); }
private:
C() {...}
// Make operator= and C(const C&) private unimplemented
// so the used cant do bad things like C c( * c_ptr );
C& operator=( const C & );
C( const C & );
};
void func()
{
C c; // This doesn't compile
shared_ptr<C> ptr = c.method(); // So you can never get this
}
void altfunc()
{
shared_ptr<C> c_ptr = C::create();
C & c_ref = *c;
shared_ptr<C> ptr = c_ref.method(); // OK
}
If you find yourself wishing for an operator= you can provide a clone function using a private implemented copy constructor, something like this
// This goes in class C
shared_ptr<C> C::clone() const
{
return shared_ptr<C>( new C(*this) );
}
// This is how you can use it
shared_ptr<C> c2 = c1->clone();
I found the solution.
In Dune library they use stack-compatible enable_shared_from_this class template adaptation.
Check the original source code here or check my example with the quick copy&paste & cleanup of code:
#include <cstdio>
#include <cassert>
#include <memory>
#include <iostream>
template<class T>
struct null_deleter
{
void operator() (T*) const {}
};
template<typename T>
inline std::shared_ptr<T> stackobject_to_shared_ptr(T & t)
{
return std::shared_ptr<T>(&t, null_deleter<T>());
}
template<typename T, typename T2>
inline std::shared_ptr<T2> stackobject_to_shared_ptr(T & t)
{
return std::shared_ptr<T2>(dynamic_cast<T2*>(&t), null_deleter<T2>());
}
template<typename T>
class stack_compatible_enable_shared_from_this
: public std::enable_shared_from_this<T>
{
public:
std::shared_ptr<T> shared_from_this()
{
try
{
return std::enable_shared_from_this<T>::shared_from_this();
}
catch (std::bad_weak_ptr&)
{
_local_ptr = stackobject_to_shared_ptr(*static_cast<T*>(this));
return _local_ptr;
}
}
std::shared_ptr<const T> shared_from_this() const
{
try
{
return std::enable_shared_from_this<T>::shared_from_this();
}
catch (std::bad_weak_ptr&)
{
_local_ptr = stackobject_to_shared_ptr(*const_cast<T*>(static_cast<const T*>(this)));
return _local_ptr;
}
}
private:
mutable std::shared_ptr<T> _local_ptr;
};
struct MyObj : public stack_compatible_enable_shared_from_this<MyObj>{};
int main (int argc, char **argv) {
//std::shared_ptr<MyObj> so = std::make_shared<MyObj>(6);
MyObj o{};
auto * so = &o;
{
auto l = std::weak_ptr<MyObj>(so->shared_from_this());
auto shared = l.lock();
if (shared) { } //use it
}
}
Related
Let say I have this class design
class A {};
class B : public A {};
class C : public A {};
and a container of A like this
std::list<A *> elements;
Now what I want to achieve is iterate through all B objects in my container, or, in another time, iterate through all C objects.
The classic way would be
for (auto it = elements.begin(); it != elements.end(); ++it) {
B * b = dynamic_cast<B *>(*it);
if (b) {
// do stuff
}
}
One idea that comes to my mind is creating an iterator class derived from standard that filters but it would be difficult.
No limits on the c++ language level (c++20 may be ok as well but it would be great to see C++11 replies).
Plain c++ and stl please (I know boost has some foreach if construct but).
A possible c++20 implementation using range
#include <iostream>
#include <list>
#include <ranges>
struct A {
virtual ~A() = default;
};
struct B : public A {
void foo() const { std::cout << "B\n"; }
};
struct C : public A {};
int main() {
std::list<A *> demo{new A{}, new B{}, new C{}, new B{}};
auto is_B = [](const A *p) { return dynamic_cast<const B *>(p) != nullptr; };
auto get_B_const = [](const A *p) { return dynamic_cast<const B *>(p); };
for (auto p_B :
demo | std::views::filter(is_B) | std::views::transform(get_B_const)) {
p_B->foo();
}
// demo destruction with delete not shown
}
Prints:
B
B
Demo: https://godbolt.org/z/6oP8hj
Note: if performance matter you can avoid using dynamic_cast two times by
auto get_B_const = [](const A *p) {
assert(dynamic_cast<const B *>(p));
return static_cast<const B *>(p);
};
I can add 2 cents: normally this smells like a design flaw ( sure there are exceptions ), this problem of "heteroganeous container", does not have a "good" solution so far. Something I have seen in th wilds is that on top of std:vector<A*> va with all elements, you may maintain another vector only with "B*" objects, std::vector<B*> vb, when it´s time to iterate go for vb when it´s time to delete go for va
One of the possible solutions without dynamic_cast. But care should be taken to state the correct type in derived class constructors.
And I would recommend to use std::unique_ptr if the list actually stores the class objects.
class Base
{
public:
enum class Type
{
A,
B,
C
};
Base() = delete;
virtual ~Base() = default;
Type type() const { return _type; }
protected:
Base(Type type) : _type{type} {}
private:
Type _type;
};
class A : public Base
{
public:
A() : Base{Base::Type::A} {}
};
class B : public Base
{
public:
B() : Base{Base::Type::B} {}
};
class C : public Base
{
public:
C() : Base{Base::Type::C} {}
};
void function()
{
std::list<std::unique_ptr<Base>> list;
list.emplace_back(std::make_unique<A>());
list.emplace_back(std::make_unique<B>());
list.emplace_back(std::make_unique<C>());
// use non-const iterators if you intend to modify the object
std::for_each(std::cbegin(list), std::cend(list),
[](const auto &item)
{
switch (item->type())
{
case Base::Type::B:
{
assert(dynamic_cast<B*>(item.get()));
const auto &b = static_cast<B*>(item.get());
// do staff with b
break;
}
default:
return;
}
});
}
I think in C++11 the way you described is as close as it gets, but I may be wrong on this. C++17 greatly extended the algorithms library, so you could use std::for_each.
To demonstrate this, let's give the classes a little bit of functionality and create a vector (or list) of instances:
class A {
public:
virtual std::string name() const = 0;
};
class B : public A {
public:
virtual std::string name() const override {
return "Class B";
}
};
class C : public A {
public:
virtual std::string name() const override {
return "Class C";
}
};
int main()
{
std::vector<A*> vec { new B(), new B(), new C(), new C(), new B() };
}
Now using for_each, you could re-write your loop:
std::for_each(std::begin(vec), std::end(vec), [](const A* val) {
auto B* b = dynamic_cast<B*>(val);
if (b)
std::cout << b->name() << std::endl;
});
Unfortunately, there is no builtin filter for any of the algorithms. You could, however, implement something like for_each_if:
template<typename Iterator, typename Predicate, typename Operation> void
for_each_if(Iterator begin, Iterator end, Predicate pred, Operation op) {
std::for_each(begin, end, [&](const auto p) {
if (pred(p))
op(p);
});
}
And use it like this:
for_each_if(std::begin(vec), std::end(vec),
[](A* val) { return dynamic_cast<B*>(val) != nullptr; },
[](const A* val) {
std::cout << val->name() << std::endl;
}
);
Or for your specific case, you could specialize the implementation even more:
template<typename T, typename Iterator, typename Operation> void
dynamic_for_each(Iterator begin, Iterator end, Operation op) {
std::for_each(begin, end, [&](auto p) {
auto tp = dynamic_cast<T>(p);
if (tp)
op(tp);
});
}
and use it like so:
dynamic_for_each<B*>(std::begin(vec), std::end(vec), [](const B* val) {
std::cout << val->name() << std::endl;
});
All three implementations print the same output:
Class B
Class B
Class B
You do not need to cast if you got the design right:
struct A {
virtual void doSomethingWithB() = 0;
virtual ~A() = default;
};
struct B : A {
void doSomethingWithB() override {
// do somehting
}
};
struct C : A {
void doSomethingWithB() override {
// do nothing !
}
};
Then your loop is simply:
for (auto elem : elements) {
elem->doSomethingWithB();
}
This does not work:
struct Type {
virtual bool func(const std::string& val) const noexcept = 0;
}
// in main
optional<Type> = some_function_returning_optional_type();
and fails with a error message:
error: cannot declare field 'std::experimental::fundamentals_v1::_Optional_base<Type, false>::<anonymous union>::_M_payload' to be of abstract type 'Type'
Changing the Type to have a non-pure function works, but is not appropriate in this case, because there cannot be an instance of Type in my code, only classes which inherit from it should be able to exist.
std::optional<T> stores its value in-place - it therefore needs to know the size of T to work correctly, and T must be a concrete type that can be instantiated. You can think of std::optional<T> as:
template <typename T>
struct optional
{
std::aligned_storage_t<sizeof(T), alignof(T)> _data;
bool _set;
};
An abstract type represents an interface - polymorphism and some sort of indirection are required to work with abstract types. std::optional doesn't have any indirection by design.
Your proposal of optional will of course work but it would offend me to have to write
x.value()->do_something();
and I'd be concerned that users might do something daft:
x.value().reset(); // now what?
We can achieve polymorphism with a non-polymorphic interface by using a wrapper.
Here's one way:
#include <optional>
#include <iostream>
// the Foo interface/base class
struct Foo
{
virtual ~Foo() = default;
virtual Foo* clone() const { return new Foo(*this); }
virtual void do_something() {
std::cout << "something Fooey\n";
}
};
// a service for managing Foo and classes derived from Foo
struct FooService
{
template<class Arg>
Foo* clone(Arg&& arg)
{
using d_type = std::decay_t<Arg>;
return new d_type(std::forward<Arg>(arg));
}
template<class Arg>
Foo* clone(Foo* arg)
{
return arg->clone();
}
Foo* release(Foo*& other) noexcept
{
auto tmp = other;
other = nullptr;
return tmp;
}
};
// implement the Foo interface in terms of a pimpl
template<class Holder>
struct BasicFoo
{
decltype(auto) do_something() {
return get().do_something();
}
private:
Foo& get() noexcept { return static_cast<Holder*>(this)->get_impl(); }
Foo const& get() const noexcept { return static_cast<Holder const*>(this)->get_impl(); }
};
// a type for holding anything derived from a Foo
// can be initialised by anything Foo-like and handles copy/move correctly
struct FooHolder : BasicFoo<FooHolder>
{
template
<
class Arg,
std::enable_if_t
<
std::is_base_of_v<Foo, std::decay_t<Arg>>
>* = nullptr
>
FooHolder(Arg&& arg)
: service_()
, ptr_(service_.clone(std::forward<Arg>(arg)))
{}
FooHolder(FooHolder const& other)
: service_()
, ptr_(other.ptr_->clone())
{
}
FooHolder(FooHolder && other) noexcept
: service_()
, ptr_(service_.release(other.ptr_))
{
}
FooHolder& operator=(FooHolder const& other)
{
auto tmp = other;
std::swap(ptr_, tmp.ptr_);
return *this;
}
FooHolder& operator=(FooHolder && other) noexcept
{
auto tmp = std::move(other);
std::swap(ptr_, tmp.ptr_);
return *this;
}
~FooHolder()
{
delete ptr_;
}
Foo& get_impl() noexcept { return *ptr_; }
Foo const& get_impl() const noexcept { return *ptr_; }
FooService service_;
Foo* ptr_;
};
// now we can supply as many overrides of Foo as we like
struct Bar : Foo
{
virtual Foo* clone() const { return FooService().clone(*this); }
virtual void do_something() {
std::cout << "something Barey\n";
}
};
int main()
{
std::optional<FooHolder> opt;
// note that we're initialising cleanly
opt = Bar {};
// and we don't expose the pointer so the user can't
// destroy the pimpl accidentally
opt.value().do_something();
}
I realize that I'll most likely get a lot of "you shouldn't do that because..." answers and they are most welcome and I'll probably totally agree with your reasoning, but I'm curious as to whether this is possible (as I envision it).
Is it possible to define a type of dynamic/generic object in C++ where I can dynamically create properties that are stored and retrieved in a key/value type of system? Example:
MyType myObject;
std::string myStr("string1");
myObject.somethingIJustMadeUp = myStr;
Note that obviously, somethingIJustMadeUp is not actually a defined member of MyType but it would be defined dynamically. Then later I could do something like:
if(myObject.somethingIJustMadeUp != NULL);
or
if(myObject["somethingIJustMadeUp"]);
Believe me, I realize just how terrible this is, but I'm still curious as to whether it's possible and if it can be done in a way that minimizes it's terrible-ness.
C++Script is what you want!
Example:
#include <cppscript>
var script_main(var args)
{
var x = object();
x["abc"] = 10;
writeln(x["abc"]);
return 0;
}
and it's a valid C++.
You can do something very similar with std::map:
std::map<std::string, std::string> myObject;
myObject["somethingIJustMadeUp"] = myStr;
Now if you want generic value types, then you can use boost::any as:
std::map<std::string, boost::any> myObject;
myObject["somethingIJustMadeUp"] = myStr;
And you can also check if a value exists or not:
if(myObject.find ("somethingIJustMadeUp") != myObject.end())
std::cout << "Exists" << std::endl;
If you use boost::any, then you can know the actual type of value it holds, by calling .type() as:
if (myObject.find("Xyz") != myObject.end())
{
if(myObject["Xyz"].type() == typeid(std::string))
{
std::string value = boost::any_cast<std::string>(myObject["Xyz"]);
std::cout <<"Stored value is string = " << value << std::endl;
}
}
This also shows how you can use boost::any_cast to get the value stored in object of boost::any type.
This can be a solution, using RTTI polymorphism
#include <map>
#include <memory>
#include <iostream>
#include <stdexcept>
namespace dynamic
{
template<class T, class E>
T& enforce(T& z, const E& e)
{ if(!z) throw e; return z; }
template<class T, class E>
const T& enforce(const T& z, const E& e)
{ if(!z) throw e; return z; }
template<class Derived>
class interface;
class aggregate;
//polymorphic uncopyable unmovable
class property
{
public:
property() :pagg() {}
property(const property&) =delete;
property& operator=(const property&) =delete;
virtual ~property() {} //just make it polymorphic
template<class Interface>
operator Interface*() const
{
if(!pagg) return 0;
return *pagg; //let the aggregate do the magic!
}
aggregate* get_aggregate() const { return pagg; }
private:
template<class Derived>
friend class interface;
friend class aggregate;
static unsigned gen_id()
{
static unsigned x=0;
return enforce(++x,std::overflow_error("too many ids"));
}
template<class T>
static unsigned id_of()
{ static unsigned z = gen_id(); return z; }
aggregate* pagg;
};
template<class Derived>
class interface: public property
{
public:
interface() {}
virtual ~interface() {}
unsigned id() const { return property::id_of<Derived>(); }
};
//sealed movable
class aggregate
{
public:
aggregate() {}
aggregate(const aggregate&) = delete;
aggregate& operator=(const aggregate&) = delete;
aggregate(aggregate&& s) :m(std::move(s.m)) {}
aggregate& operator=(aggregate&& s)
{ if(this!=&s) { m.clear(); std::swap(m, s.m); } return *this; }
template<class Interface>
aggregate& add_interface(interface<Interface>* pi)
{
m[pi->id()] = std::unique_ptr<property>(pi);
static_cast<property*>(pi)->pagg = this;
return *this;
}
template<class Inteface>
aggregate& remove_interface()
{ m.erase[property::id_of<Inteface>()]; return *this; }
void clear() { m.clear(); }
bool empty() const { return m.empty(); }
explicit operator bool() const { return empty(); }
template<class Interface>
operator Interface*() const
{
auto i = m.find(property::id_of<Interface>());
if(i==m.end()) return nullptr;
return dynamic_cast<Interface*>(i->second.get());
}
template<class Interface>
friend aggregate& operator<<(aggregate& s, interface<Interface>* pi)
{ return s.add_interface(pi); }
private:
typedef std::map<unsigned, std::unique_ptr<property> > map_t;
map_t m;
};
}
/// this is a sample on how it can workout
class interface_A: public dynamic::interface<interface_A>
{
public:
virtual void methodA1() =0;
virtual void methodA2() =0;
};
class impl_A1: public interface_A
{
public:
impl_A1() { std::cout<<"creating impl_A1["<<this<<"]"<<std::endl; }
virtual ~impl_A1() { std::cout<<"deleting impl_A1["<<this<<"]"<<std::endl; }
virtual void methodA1() { std::cout<<"interface_A["<<this<<"]::methodA1 on impl_A1 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodA2() { std::cout<<"interface_A["<<this<<"]::methodA2 on impl_A1 in aggregate "<<get_aggregate()<<std::endl; }
};
class impl_A2: public interface_A
{
public:
impl_A2() { std::cout<<"creating impl_A2["<<this<<"]"<<std::endl; }
virtual ~impl_A2() { std::cout<<"deleting impl_A2["<<this<<"]"<<std::endl; }
virtual void methodA1() { std::cout<<"interface_A["<<this<<"]::methodA1 on impl_A2 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodA2() { std::cout<<"interface_A["<<this<<"]::methodA2 on impl_A2 in aggregate "<<get_aggregate()<<std::endl; }
};
class interface_B: public dynamic::interface<interface_B>
{
public:
virtual void methodB1() =0;
virtual void methodB2() =0;
};
class impl_B1: public interface_B
{
public:
impl_B1() { std::cout<<"creating impl_B1["<<this<<"]"<<std::endl; }
virtual ~impl_B1() { std::cout<<"deleting impl_B1["<<this<<"]"<<std::endl; }
virtual void methodB1() { std::cout<<"interface_B["<<this<<"]::methodB1 on impl_B1 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodB2() { std::cout<<"interface_B["<<this<<"]::methodB2 on impl_B1 in aggregate "<<get_aggregate()<<std::endl; }
};
class impl_B2: public interface_B
{
public:
impl_B2() { std::cout<<"creating impl_B2["<<this<<"]"<<std::endl; }
virtual ~impl_B2() { std::cout<<"deleting impl_B2["<<this<<"]"<<std::endl; }
virtual void methodB1() { std::cout<<"interface_B["<<this<<"]::methodB1 on impl_B2 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodB2() { std::cout<<"interface_B["<<this<<"]::methodB2 on impl_B2 in aggregate "<<get_aggregate()<<std::endl; }
};
int main()
{
dynamic::aggregate agg1;
agg1 << new impl_A1 << new impl_B1;
dynamic::aggregate agg2;
agg2 << new impl_A2 << new impl_B2;
interface_A* pa = 0;
interface_B* pb = 0;
pa = agg1; if(pa) { pa->methodA1(); pa->methodA2(); }
pb = *pa; if(pb) { pb->methodB1(); pb->methodB2(); }
pa = agg2; if(pa) { pa->methodA1(); pa->methodA2(); }
pb = *pa; if(pb) { pb->methodB1(); pb->methodB2(); }
agg2 = std::move(agg1);
pa = agg2; if(pa) { pa->methodA1(); pa->methodA2(); }
pb = *pa; if(pb) { pb->methodB1(); pb->methodB2(); }
return 0;
}
tested with MINGW4.6 on WinXPsp3
Yes it is terrible. :D
It had been done numerous times to different extents and success levels.
QT has Qobject from which everything related to them decends.
MFC has CObject from which eveything decends as does C++.net
I don't know if there is a way to make it less bad, I guess if you avoid multiple inheritance like the plague (which is otherwise a useful language feature) and reimplement the stdlib it would be better. But really if that is what you are after you are probably using the wrong language for the task.
Java and C# are much better suited to this style of programming.
#note if I have read your question wrong just delete this answer.
Check out Dynamic C++
I am trying to mimic a finally like effect. So i thought i should run a quick dirty test.
The idea was to use Most Important const to stop destruction and to put the finally block in a lambda. However apparently i did something wrong and its being called at the end of MyFinally(). How do i solve this problem?
#include <cassert>
template<typename T>
class D{
T fn;
public:
D(T v):fn(v){}
~D(){fn();}
};
template<typename T>
const D<T>& MyFinally(T t) { return D<T>(t); }
int d;
class A{
int a;
public:
void start(){
int a=1;
auto v = MyFinally([&]{a=2;});
try{
assert(a==1);
//do stuff
}
catch(int){
//do stuff
}
}
};
int main() {
A a;
a.start();
}
My Solution code (Note: You can not have two finally in the same block. as expect. But still kind of dirty)
#include <cassert>
template<typename T>
class D{
T fn; bool exec;
public:
D(T v):fn(v),exec(true){}
//D(D const&)=delete //VS doesnt support this yet and i didnt feel like writing virtual=0
D(D &&d):fn(move(d.fn)), exec(d.exec) {
d.exec = false;
}
~D(){if(exec) fn();}
};
template<typename T>
D<T> MyFinally(T t) { return D<T>(t); }
#define FINALLY(v) auto OnlyOneFinallyPlz = MyFinally(v)
int d;
class A{
public:
int a;
void start(){
a=1;
//auto v = MyFinally([&]{a=2;});
FINALLY([&]{a=2;});
try{
assert(a==1);
//do stuff
}
catch(int){
FINALLY([&]{a=3;}); //ok, inside another scope
try{
assert(a==1);
//do other stuff
}
catch(int){
//do other stuff
}
}
}
};
void main() {
A a;
a.start();
assert(a.a==2);
}
Funny enough, if you remove the & in MyFinally in the original code it works -_-.
// WRONG! returning a reference to a temporary that will be
// destroyed at the end of the function!
template<typename T>
const D<T>& MyFinally(T t) { return D<T>(t); }
You can fix it my introducing a move constructor
template<typename T>
class D{
T fn;
bool exec;
public:
D(T v):fn(move(v)),exec(true){}
D(D &&d):fn(move(d.fn)), exec(d.exec) {
d.exec = false;
}
~D(){if(exec) fn();}
};
And then you can rewrite your toy
template<typename T>
D<T> MyFinally(T t) { return D<T>(move(t)); }
Hope it helps. No "const reference" trick is needed when you work with auto. See here for how to do it in C++03 with const references.
Your code and Sutter's are not equivalent. His function returns a value, yours returns a reference to an object that will be destroyed when the function exits. The const reference in the calling code does not maintain the lifetime of that object.
The problem stems from the use of a function maker, as demonstrated by Johannes.
I would argue that you could avoid the issue by using another C++0x facility, namely std::function.
class Defer
{
public:
typedef std::function<void()> Executor;
Defer(): _executor(DoNothing) {}
Defer(Executor e): _executor(e) {}
~Defer() { _executor(); }
Defer(Defer&& rhs): _executor(rhs._executor) {
rhs._executor = DoNothing;
}
Defer& operator=(Defer rhs) {
std::swap(_executor, rhs._executor);
return *this;
}
Defer(Defer const&) = delete;
private:
static void DoNothing() {}
Executor _executor;
};
Then, you can use it as simply:
void A::start() {
a = 1;
Defer const defer([&]() { a = 2; });
try { assert(a == 1); /**/ } catch(...) { /**/ }
}
Well the problem is explained by others, so I will suggest a fix, exactly in the same way Herb Sutter has written his code (your code is not same as his, by the way):
First, don't return by const reference:
template<typename T>
D<T> MyFinally(T t)
{
D<T> local(t); //create a local variable
return local;
}
Then write this at call site:
const auto & v = MyFinally([&]{a=2;}); //store by const reference
This became exactly like Herb Sutter's code.
Demo : http://www.ideone.com/uSkhP
Now the destructor is called just before exiting the start() function.
A different implementation which doesn't use auto keyword anymore:
struct base { virtual ~base(){} };
template<typename TLambda>
struct exec : base
{
TLambda lambda;
exec(TLambda l) : lambda(l){}
~exec() { lambda(); }
};
class lambda{
base *pbase;
public:
template<typename TLambda>
lambda(TLambda l): pbase(new exec<TLambda>(l)){}
~lambda() { delete pbase; }
};
And use it as:
lambda finally = [&]{a=2; std::cout << "finally executed" << std::endl; };
Looks interesting?
Complete demo : http://www.ideone.com/DYqrh
You could return a shared_ptr:
template<typename T>
std::shared_ptr<D<T>> MyFinally(T t) {
return std::shared_ptr<D<T>>(new D<T>(t));
}
Following code does NOT work, but it expresses well what I wish to do. There is a problem with the template struct container, which I think SHOULD work because it's size is known for any template argument.
class callback {
public:
// constructs a callback to a method in the context of a given object
template<class C>
callback(C& object, void (C::*method)())
: ptr.o(object), ptr.m(method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
template<class C>
struct {
C& o;
void (C::*m)();
} ptr;
};
Is there any way to do such a thing? I mean have a non-template class callback which wraps any pointer to method?
Thanks C++ gurus!
Edit:
Please see this:
Callback in C++, template member? (2)
This is a complete working example that does what I think you're trying to do:
#include <iostream>
#include <memory>
// INTERNAL CLASSES
class CallbackSpecBase
{
public:
virtual ~CallbackSpecBase() {}
virtual void operator()() const = 0;
};
template<class C>
class CallbackSpec : public CallbackSpecBase
{
public:
CallbackSpec(C& o, void (C::*m)()) : obj(o), method(m) {}
void operator()() const { (&obj->*method)(); }
private:
C& obj;
void (C::*method)();
};
// PUBLIC API
class Callback
{
public:
Callback() {}
void operator()() { (*spec)(); }
template<class C>
void set(C& o, void (C::*m)()) { spec.reset(new CallbackSpec<C>(o, m)); }
private:
std::auto_ptr<CallbackSpecBase> spec;
};
// TEST CODE
class Test
{
public:
void foo() { std::cout << "Working" << std::endl; }
void bar() { std::cout << "Like a charm" << std::endl; }
};
int main()
{
Test t;
Callback c;
c.set(t, &Test::foo);
c();
c.set(t, &Test::bar);
c();
}
I recently implemented this:
#define UNKOWN_ITEM 0xFFFFFFFF
template <typename TArg>
class DelegateI
{
public:
virtual void operator()(TArg& a)=0;
virtual bool equals(DelegateI<TArg>* d)=0;
};
template <class TArg>
class Event
{
public:
Event()
{
}
~Event()
{
for (size_t x=0; x<m_vDelegates.size(); x++)
delete m_vDelegates[x];
}
void operator()(TArg& a)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
m_vDelegates[x]->operator()(a);
}
}
void operator+=(DelegateI<TArg>* d)
{
if (findInfo(d) != UNKOWN_ITEM)
{
delete d;
return;
}
m_vDelegates.push_back(d);
}
void operator-=(DelegateI<TArg>* d)
{
uint32 index = findInfo(d);
delete d;
if (index == UNKOWN_ITEM)
return;
m_vDelegates.erase(m_vDelegates.begin()+index);
}
protected:
int findInfo(DelegateI<TArg>* d)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
if (m_vDelegates[x]->equals(d))
return (int)x;
}
return UNKOWN_ITEM;
}
private:
std::vector<DelegateI<TArg>*> m_vDelegates;
};
template <class TObj, typename TArg>
class ObjDelegate : public DelegateI<TArg>
{
public:
typedef void (TObj::*TFunct)(TArg&);
ObjDelegate(TObj* t, TFunct f)
{
m_pObj = t;
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
ObjDelegate<TObj,TArg> *d = dynamic_cast<ObjDelegate<TObj,TArg>*>(di);
if (!d)
return false;
return ((m_pObj == d->m_pObj) && (m_pFunct == d->m_pFunct));
}
virtual void operator()(TArg& a)
{
if (m_pObj && m_pFunct)
{
(*m_pObj.*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
TObj* m_pObj; // pointer to object
};
template <typename TArg>
class FunctDelegate : public DelegateI<TArg>
{
public:
typedef void (*TFunct)(TArg&);
FunctDelegate(TFunct f)
{
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
FunctDelegate<TArg> *d = dynamic_cast<FunctDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pFunct == d->m_pFunct);
}
virtual void operator()(TArg& a)
{
if (m_pFunct)
{
(*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
};
template <typename TArg>
class ProxieDelegate : public DelegateI<TArg>
{
public:
ProxieDelegate(Event<TArg>* e)
{
m_pEvent = e;
}
virtual bool equals(DelegateI<TArg>* di)
{
ProxieDelegate<TArg> *d = dynamic_cast<ProxieDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pEvent == d->m_pEvent);
}
virtual void operator()(TArg& a)
{
if (m_pEvent)
{
(*m_pEvent)(a);
}
}
Event<TArg>* m_pEvent; // pointer to member function
};
template <class TObj, class TArg>
DelegateI<TArg>* delegate(TObj* pObj, void (TObj::*NotifyMethod)(TArg&))
{
return new ObjDelegate<TObj, TArg>(pObj, NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(void (*NotifyMethod)(TArg&))
{
return new FunctDelegate<TArg>(NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(Event<TArg>* e)
{
return new ProxieDelegate<TArg>(e);
}
use it like so:
define:
Event<SomeClass> someEvent;
enlist callbacks:
someEvent += delegate(&someFunction);
someEvent += delegate(classPtr, &class::classFunction);
someEvent += delegate(&someOtherEvent);
trigger:
someEvent(someClassObj);
You can also make your own delegates and overide what they do. I made a couple of others with one being able to make sure the event triggers the function in the gui thread instead of the thread it was called.
You need to use polymorphism. Use an abstract base class with a virtual invocation method (operator() if you please), with a templated descendant that implements the virtual method using the correct type signature.
The way you have it now, the data holding the type is templated, but the code meant to invoke the method and pass the object isn't. That won't work; the template type parameters need to flow through both construction and invocation.
#Barry Kelly
#include <iostream>
class callback {
public:
virtual void operator()() {};
};
template<class C>
class callback_specialization : public callback {
public:
callback_specialization(C& object, void (C::*method)())
: o(object), m(method) {}
void operator()() {
(&o ->* m) ();
}
private:
C& o;
void (C::*m)();
};
class X {
public:
void y() { std::cout << "ok\n"; }
};
int main() {
X x;
callback c(callback_specialization<X>(x, &X::y));
c();
return 0;
}
I tried this, but it does not work (print "ok")... why?
Edit:
As Neil Butterworth mentioned, polymorphism works through pointers and references,
X x;
callback& c = callback_specialization<X>(x, &X::y);
c();
Edit:
With this code, I get an error:
invalid initialization of non-const reference of type ‘callback&’
from a temporary of type ‘callback_specialization<X>’
Now, I don't understand that error, but if I replace callback& c with const callback& c and virtual void operator()() with virtual void operator()() const, it works.
You didn't say what errors you found, but I found that this worked:
template<typename C>
class callback {
public:
// constructs a callback to a method in the context of a given object
callback(C& object, void (C::*method)())
: ptr(object,method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
// template<class C>
struct Ptr{
Ptr(C& object, void (C::*method)()): o(object), m(method) {}
C& o;
void (C::*m)();
} ptr;
};
Note that Ptr needs a constructor as it has a reference member.
You could do without struct Ptr and have the raw members.
Tested with VS2008 express.
Improving the OP's answer:
int main() {
X x;
callback_specialization<X> c(x, &X::y);
callback& ref(c);
c();
return 0;
}
This prints "ok".
Tested on VS2008 express.
Please see this
Callback in C++, template member? (2)