Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::any_cast and user defined type

36 views
Skip to first unread message

Mark

unread,
May 16, 2019, 8:53:19 PM5/16/19
to
Given

#include <iostream>
#include <vector>
#include <memory>
#include <tuple>
#include <any>
#include <functional>

//deducing the tuple type from the function type
// e.g: std::function<void(float, double)> => std::tuple<float, double>
template <typename T>
struct tuple_desc;
template <typename R, typename... Args>
struct tuple_desc<std::function<R(Args...)>> {
using type = std::tuple<Args...>;
};

// deducing the function signature from the callable
template <typename Callable>
using function_class = decltype(std::function(std::declval<Callable>()));

class Observable {

class Observable_model { // type neutral hook
public:
virtual void notify(unsigned event_number, std::any& argument_wrapper) = 0;
virtual ~Observable_model() = default;
};

template <typename Callback>
class Observable_object : public Observable_model { // stores concrete type information
public:
Observable_object(unsigned event_class, const Callback& cbk) : event_class(event_class), callback(cbk) {}

void notify(unsigned event_number, std::any& argument_wrapper) override {
using Arg_tuple = typename tuple_desc<decltype(this->callback)>::type; // so tuple<int, float> for [](int a, float b) { /*...*/ }
if (event_number == event_class) { // dynamic dispatch
std::apply(callback, std::any_cast<Arg_tuple> (argument_wrapper));
}
}
private:
unsigned event_class;
function_class<Callback> callback;
};

public:
template <typename Callback>
void attach(unsigned event_class, Callback&& callback) {
auto new_obj = std::make_unique<Observable_object<Callback>>(event_class, callback);
observations.push_back(std::move(new_obj));
}
template <typename... Args>
void notify(unsigned event_number, Args&&... args) {
std::tuple<Args...> arg_tuple(std::forward<Args>(args)...);
std::any argument_wrapper(arg_tuple); // argument type erasure
for (auto& obs : observations) obs->notify(event_number, argument_wrapper);
}

private:
std::vector<std::unique_ptr<Observable_model>> observations;

};

// testing the interface;

enum { WILDLIFE = 0, MACHINES = 1 };

struct Foo {};
struct Bar {};


struct Buzzer {
void go(int h) { std::cout << "drrrr... drrrr... it's " << h << " a.m, time to wake up!\n"; }
void go(Foo& ) { std::cout << "drrrr... drrrr... it's Foo!\n"; }
void go(Bar& ) { std::cout << "drrrr... drrrr... it's Bar!\n"; }
};
struct Coffee_machine {
void make_coffee(int h) { if (h == 7) std::cout << "time to make coffee!\n"; else std::cout << "no coffee yet baby!\n"; }
};

struct Rooster {
void sing() { std::cout << "Cocorico!\n"; }
};


struct Vampire {
void bury() { std::cout << "Bye! I'll be in my grave!\n"; }
};

struct Sun : public Observable {
void rise() {
std::cout << "Waouh, the sun rises!\n";
notify(WILDLIFE);
//Foo f ;
//notify(MACHINES, f);
notify(MACHINES, 6);
}
};



int main() {
Sun sun;
Buzzer buzzer;
Rooster rooster;
Vampire vampire;

Coffee_machine coffee_machine;
sun.attach(WILDLIFE, [&rooster] {rooster.sing();});
sun.attach(WILDLIFE, [&vampire] {vampire.bury();});
sun.attach(MACHINES, [&buzzer](int h) {buzzer.go(h);});
sun.attach(MACHINES, [&buzzer](Foo& f ) {buzzer.go(f);});
sun.attach(MACHINES, [&coffee_machine](int h) {coffee_machine.make_coffee(h);});
sun.rise();

#if 0
// This makes no sense.. why would this not work....
//I'm being explicit that I want the Bar& overload ..
using std::placeholders::_1 ;
std::function < void (Bar&)> lFunc = std::bind(&Buzzer::go, buzzer, _1 ) ;
sun.attach(MACHINES, lFunc ) ;
#endif
}



Code compiles and runs but exception (bad any_cast) is generated for Foo user define type. Assuming I'm not off on this , Foo is has an implicit copy constructor so not sure why 'bad any_cast'. How to solve?

Also why would std::function < void (Bar&)> lFunc = std::bind(&Buzzer::go, buzzer, _1 ) ; result in a compilation error when std::function < void (Bar&)> is explicit in terms of the method to call?

Mr Flibble

unread,
May 17, 2019, 9:18:43 AM5/17/19
to
I think you need a cast where you take the address of Buzzer:go.

/Flibble

--
“You won’t burn in hell. But be nice anyway.” – Ricky Gervais

“I see Atheists are fighting and killing each other again, over who
doesn’t believe in any God the most. Oh, no..wait.. that never happens.” –
Ricky Gervais

"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."

Mr Flibble

unread,
May 17, 2019, 9:33:27 AM5/17/19
to
Also, why are you using std::bind? We have lambdas now.

Sal LO

unread,
May 19, 2019, 5:59:54 PM5/19/19
to
0 new messages