This is my code (simplification of a real-life problem):
class Foo {
public:
void f(const string& s) {
if (s == "lt") {
return lt();
} else if (s == "lte")
return lte();
} else if (s == "gt")
return gt();
} else if (s == "gte")
return gte();
}
}
void lt() { /* skipped */ }
void lte() { /* skipped */ }
void gt() { /* skipped */ }
void gte() { /* skipped */ }
};
This is how I would do it in PHP/Python/JavaScript/many other languages (example in PHP):
class Foo {
function f($s) {
return $this->$s();
}
function lt() { /* skipped */ }
function lte() { /* skipped */ }
function gt() { /* skipped */ }
function gte() { /* skipped */ }
}
How can I make my C++ code as elegant as this PHP example? Thanks in advance.
There is no reflection in C++. However, something like a std::map<std::string, void (Foo::*)()>should do the trick.
EDIT: Here is some ugly code to do it maintainably. Note the following :
This can probably be improved in various way
Please add code to deal with non-existent tokens. I did no error checking.
#define BEGIN_TOKEN_MAP \
template <int n> \
struct add_to_ \
{ \
static void act() {} \
}; \
std::map<std::string, void (Foo::*)()> map_;
#define DECLARE_TOKEN(str, n) \
template <> struct add_to_<n> \
{ \
static void act() { map_[#str] = &Foo::##str; add_to<n+1>::act();} \
};\
void str()
#define END_TOKEN_MAP \
void init_map() { add_to_<0>::act(); } \
void process_token(std::string s) { (this->*map_[s])(); }
class Foo
{
BEGIN_TOKEN_MAP
DECLARE_TOKEN(lt, 0) { ... }
DECLARE_TOKEN(gt, 1) { ... }
...
END_TOKEN_MAP
Foo() { init_map(); }
void f(const std::string& s) { process_token(s); }
};
You could use a dispatch table like:
typedef struct {
char *name;
void (*handler)();
} handler_t;
handler_t *handlers = {
{"lt", <},
{"lte", <e},
{"gt", >},
{"gte", >e},
(NULL, NULL}
};
void f(const string &s) {
for (int i=0; handlers[i].handler; ++i) {
if (0 == strcmp(s.c_str(), handlers[i].name)) {
handlers[i].handler();
return;
}
}
}
See also this SO question: How do you implement a dispatch table in your language of choice?
C++ is not dynamic, so there is no exact equivalent. A little more elegant would be to use a map and possibly function objects.
Following with the suggestion from Alexandre C., you can combine the std::map<... approach with an operator() to avoid having to call through to the void Foo::f.
For example:
class Foo {
private:
map<string,void (Foo::*)()> funs;
public:
// constructors etc.
void operator () (const string& s) {
if (funs.find (s) != funs.end ())
(this->*funs[s])();
}
// remainder
};
And you can now use foo similar to
Foo f;
f("lt"); // calls Foo::lt ()
f("lte"); // calls Foo::lte ();
// etc...
// Beware, brain-compiled code ahead!
namespace {
typedef std::map<std::string, void (Foo::*)()> operations_map_t;
typedef operations_map_t::value_type operations_entry_t;
const operations_entry_t* operations = { {"lt" , &Foo::lt }
, {"lte", &Foo::lte}
, {"gt" , &Foo::gt }
, {"gte", &Foo::gte} };
const operations_map_t operations_map( operations
, operations + sizeof(operations)
/ sizeof(operations[0]) );
}
void Foo::f(const string& s)
{
operations_map_t::const_iterator it = operations_map.find(s);
if(it == operations_map.end()) throw "Dooh!";
it->second();
}
I've upvoted Alexandre C, but I have reservations about building a data structure at run-time (populating the std::map) when the data is all known at compile-time.
I've upvoted the_void, but a linear search is only appropriate for relatively small data sets.
One option worth considering is a script (written in e.g. Python) to generate a hash-table or perfectly-balanced binary tree or whatever at build-time. You'll only do it if you have a recurring need to support large known-at-compile-time datasets, of course.
There's probably template-trickery ways to do this in C++ - they are Turing complete, and theres at least one compile-time parser state model generator, which is clearly more complex than a hash-table or binary tree. But personally, I wouldn't recommend it. A code-generating script will be simpler and more robust.
I have a script for generating ternary trees, but (1) it's a bit long for here, and (2) its not exactly a shining example of good coding.
You have several possibilities. But the first thing I should say is that C++ is strongly typed. Therefore a method that handles an instance of Foo on the one hand and Foo on the other hand is of a different type from of method that handles Foo and Bar.
Now, let's suppose that you only wish to handle Foo objects. Then you have 2 solutions:
function pointers
function objects
The function object is more general, notably, it would allow you to specify multiple combinations of parameters in one object.
class OperatorBase
{
public:
virtual ~OperatorBase() {}
bool operator()(Foo const& lhs, Foo const& rhs) const;
bool operator()(Foo const& lhs, Bar const& rhs) const;
bool operator()(Bar const& lhs, Foo const& rhs) const;
bool operator()(Bar const& lhs, Bar const& rhs) const;
private:
// virtual methods to actually implement this
};
struct LessThanOperator: OperatorBase
{
// impl
};
class OperatorFactory
{
public:
static OperatorBase& Get(std::string const& name);
template <class T>
static void Register(std::string const& name);
private:
typedef boost::ptr_map<std::string, OperatorBase> ops_t;
static ops_t& Get() { static ops_t O; return O; }
};
And then you can proceed:
// Choose the operator
OperatorBase& op = OperatorFactory::Get("lt");
Foo foo;
Bar bar;
bool const result = op(foo, bar);
It's quite tedious work though.
There are ways to do similar things in C++ with arrays and dynamic dispatch.
What you do is create an abstract class with some standard action(), like so:
class abstract_handler {
public:
virtual void action () = 0;
}
Then you create subclasses with different implementations of action(). For example, for your "ffa" branch you might write:
class ffa_handler : public abstract_handler {
public:
virtual action() {
// Do your custom "ffa" stuff in here
}
// Add your custom "ffa" members for action() to work on here.
// ...and of course a constructor to initialize them.
}
Then you create a map (in your case, indexed by std::string) of pointers to objects of each of your classes. At startup you populate this with the proper objects on the proper string indices. Then at runtime all you have to do is:
handler_map[index_string].action();
Related
I am writing an interface for several I/O classes.
There is a function that looks for information in different kinds of files (sometimes html, sdb, txt, ...):
bool Search(std::string file, std::string field)
However, one of these requires an additional parameter to complement the SQL query. In this case the sdb needs to specify in what table the field is located.
I am trying something like the following (it does not compile, I am aware):
class fileIO{
public:
virtual ~FileIO(){};
virtual bool Search(std::string file, std::string field,
std::string additional = 0 /* for sdb only */) = 0;
}
class readHTML : fileIO{
public:
bool Search(std::string file, std::string field); //does NOT override virtual method
Is there anything that can give me the behavior I am looking for?
Is such strategy according to C++ standards?
What else could I add to replace such enforcement on the interface?
I am sorry if the title is misleading, I am looking for an alternative with that behavior. I could not find it so far.
You don't need it, I'd say.
At the caller site, there is only two possibilities: you know your specific fileIO instance is a sdbIO or you don't. If you do, you can call an overloaded version of Search defined in sdbIO which takes this additional info. If you don't, you don't and sdbIO::Search should be defined in terms of its overloaded version.
struct fileIO
{
virtual bool Search(std::string file, std::string field) = 0;
}
struct sdbIO : fileIO
{
bool Search(std::string file, std::string field, std::string additional);
bool Search(std::string file, std::string field) override
{
Search(file, field, "");
}
};
At the caller site:
void f(fileIO& io)
{
// I know this is a sdb:
dynamic_cast<sdbIO&>(io).Search("/file", "text", "WHERE answer=42");
// I don't
io.Search("/file", "text");
}
notes: do you really need a copy of those strings?
You can hide the virtual function in the non-public interface and make the public interface (with the default argument) non-virtual.
struct Interface
{
...
// public interface calls the abstract members.
bool Search(string const&a, string const&b, string const&c = "")
{
if(c.empty() && need_third_string())
throw runtime_error("search requires an additional string argument");
return search(a,b,c);
}
protected:
virtual bool need_third_string() const = 0;
virtual bool search(string const&, string const&, string const&) const=0;
};
with obvious derivations:
struct A : Interface
{
protected:
bool need_third_string() const override
{ return false; }
bool search(string const&a, string const&b, string const&) const override
{ /* search ignoring third argument */ }
};
struct B : Interface
{
protected:
bool need_third_string() const override
{ return true; }
bool search(string const&a, string const&b, string const&c) const override
{ /* search ignoring using all 3 arguments */ }
};
I don't see any problem with above two way to handle things. Still, I have just one more.
#include<bits/stdc++.h>
#include <stdexcept>
using namespace std;
typedef struct
{
std::string arg1;
std::string arg2;
std::string arg3;
} Param;
class FileIO{
public:
virtual ~FileIO(){};
virtual void Search(Param param) = 0;
};
class ReadHTML : public FileIO{
public:
void Search(Param param)
{
if(param.arg3.length() > 0) // Some logic to handle things here.
search3(param.arg1, param.arg2, param.arg3);
else
throw std::runtime_error("Bad call with param");
}
private:
void search3(std::string arg1, std::string arg2, std::string arg3)
{
std::cout << " I am called with Html::Search3" << std::endl;
}
};
class ReadTxt : public FileIO{
public:
void Search(Param param)
{
if(param.arg1.length() && param.arg2.length()) // Some logic to handle things here.
search2(param.arg1, param.arg2);
else
throw std::runtime_error("Bad call with param");
}
private:
void search2(std::string arg1, std::string arg2)
{
std::cout << " I am called with Txt::Search2" << std::endl;
}
};
// Driver program to test above function
int main()
{
FileIO *io = new ReadHTML();
Param paramHtml = {"a", "b", "c"};
io->Search(paramHtml); // Put some try .. catch
Param paramTxt = {"a", "b"};
io = new ReadTxt(); // Put some try...catch
io->Search(paramTxt);
return 0;
}
I'd like to simplify the code I write in my application that handles mutiple data structure types but with a common header. Given something like this:
enum class MyType {
Foo = 100,
Bar = 200,
};
struct Hdr {
MyType type;
};
struct Foo {
Hdr hdr;
int x;
int y;
int z;
};
struct Bar {
Hdr hdr;
double value;
double ratio;
};
void process(const Foo *ptr)
{
// process Foo here
}
void process(const Bar *ptr)
{
// process Bar here
}
extern void *getData();
int main()
{
const void *pv = getData();
auto pHdr = static_cast<const Hdr *>(pv);
switch (pHdr->type) {
case MyType::Foo: process(static_cast<const Foo *>(pv)); break;
case MyType::Bar: process(static_cast<const Bar *>(pv)); break;
default: throw "Unknown";
}
return 0;
}
Ideally I'd like to replace the switch statement above with something like:
process(multi_cast<pHdr->type>(pv);
I'm perfectly okay with having to write statements like this to get it to work:
template<MyType::Foo>
const Foo *multi_cast(void *p)
{
return static_cast<const Foo *>(p);
}
template<MyType::Bar>
const Bar *multi_cast(void *p)
{
return static_cast<const Bar *>(p);
}
But I cannot write a template where the template parameter is a enum (or an int for that matter)
Have I just looked at this for so long that I cannot see an answer?
Or is there just no other way to do it?
There is just no other way to do it.
As the comments have pointed out, since the type is stored in the header at run-time, you have to have some kind of run-time lookup; no amount of templates or overload resolution can help you since all of that is at compile-time.
You can abstract the lookup as much as you want, but you can only replace the switch statement with another type of lookup, and you can only decrease performance the further you get away from a simple switch/lookup table.
For example, you could start with something like this and go nuts:
#include <iostream>
#include <cassert>
enum class Type {
FOO,
BAR,
NUM_
};
struct Header {
Header(Type t)
: type(t)
{}
Type type;
};
struct Foo {
Foo(int x, int y, int z)
: header(Type::FOO), x(x), y(y), z(z)
{}
Header header;
int x;
int y;
int z;
};
struct Bar {
Bar(double value, double ratio)
: header(Type::BAR), value(value), ratio(ratio)
{}
Header header;
double value;
double ratio;
};
static inline void process(Foo*) {
printf("processing foo...\n");
}
static inline void process(Bar*) {
printf("processing bar...\n");
}
using ProcessFunc = void(*)(void*);
static ProcessFunc typeProcessors[(size_t)Type::NUM_] = {
[](void* p) { process((Foo*)p); },
[](void* p) { process((Bar*)p); },
};
static void process(void* p) {
Type t = ((Header*)p)->type;
assert((size_t)t < (size_t)Type::NUM_ && "Invalid Type.");
typeProcessors[(size_t)t](p);
}
static void* get_foo()
{
static Foo foo(0, 0, 0);
return &foo;
}
static void* get_bar()
{
static Bar bar(0.0, 0.0);
return &bar;
}
int main() {
Foo foo(0, 0, 0);
Bar bar(0.0, 0.0);
process(&foo);
process(&bar);
process(get_foo());
process(get_bar());
return 0;
}
but then you're only getting cute and most likely slower. You might as well just put the switch in process(void*)
If you aren't serializing your data(doubtful), are mostly processing one type at a time, and want an OO solution(I wouldn't), you could return a base type that your types inherit from and add a pure virtual process function like so:
struct Type {
virtual void process() = 0;
virtual ~Type() {}
};
struct Foo : Type {
int x = 0;
int y = 0;
int z = 0;
virtual void process() override {
printf("processing foo...\n");
}
};
struct Bar : Type {
double value = 0.0;
double ratio = 0.0;
virtual void process() override {
printf("processing bar...\n");
}
};
static Type* get_foo() {
static Foo foo;
return &foo;
}
static Type* get_bar() {
static Bar bar;
return &bar;
}
int main() {
Foo foo;
Bar bar;
foo.process();
bar.process();
get_foo()->process();
get_bar()->process();
return 0;
}
I would stick with the switch, but I would keep the values of Type::FOO and Type::BAR the default 0 and 1. If you mess with the values too much, the compiler might decide to implement the switch as a bunch of branches as opposed to a lookup table.
You have two issues:
Converting a runtime value (your "type") into a compile time determined type (with associated behavior).
"Unifying" the possible different types to a single (statically at compile time known) type.
Point 2 is what inheritance together with virtual member functions are for:
struct Thing {
virtual void doStuff() const = 0;
virtual ~Thing() {}
};
struct AThing : Thing {
void doStuff() const override { std::cout << "A"; }
};
struct BThing : Thing {
void doStuff() const override { std::cout << "B"; }
};
Point 1 is usually tackled by creating some kind of "factory" mechanism, and then dispatching based on the runtime value to one of those factories. First, the factories:
Thing * factoryA() { return new AThing(); }
Thing * factoryB() { return new BThing(); }
Thing * factory_failure() { throw 42; }
The "dispatching" (or "choosing the right factory") can be done in different ways, one of those being your switch statement (fast, but clumsy), linear search through some container/array (easy, slow) or by lookup in a map (logarithmic - or constant for hashing based maps).
I chose a (ordered) map, but instead of using std::map (or std::unordered_map) I use a (sorted!) std::array to avoid dynamic memory allocation:
// Our "map" is nothing more but an array of key value pairs.
template <
typename Key,
typename Value,
std::size_t Size>
using cmap = std::array<std::pair<Key,Value>, Size>;
// Long type names make code hard to read.
template <
typename First,
typename... Rest>
using cmap_from =
cmap<typename First::first_type,
typename First::second_type,
sizeof...(Rest) + 1u>;
// Helper function to avoid us having to specify the size
template <
typename First,
typename... Rest>
cmap_from<First, Rest...> make_cmap(First && first,
Rest && ... rest) {
return {std::forward<First>(first), std::forward<Rest>(rest)...};
}
Using std::lower_bound I perform a binary search on this sorted array (ehm "map"):
// Binary search for lower bound, check for equality
template <
typename Key,
typename Value,
std::size_t Size>
Value get_from(cmap<Key,Value,Size> const & map,
Key const & key,
Value alternative) {
assert(std::is_sorted(std::begin(map), std::end(map),
[](auto const & lhs, auto const & rhs) {
return lhs.first < rhs.first; }));
auto const lower = std::lower_bound(std::begin(map), std::end(map),
key,
[](auto const & pair, auto k) {
return pair.first < k; });
if (lower->first == key) {
return lower->second;
} else {
// could also throw or whatever other failure mode
return alternative;
}
}
So that, finally, I can use a static const map to get a factory given some runtime value "type" (or choice, as I named it):
int main() {
int const choices[] = {1, 10, 100};
static auto const map =
make_cmap(std::make_pair(1, factoryA),
std::make_pair(10, factoryB));
try {
for (int choice : choices) {
std::cout << "Processing choice " << choice << ": ";
auto const factory = get_from(map, choice, factory_failure);
Thing * thing = factory();
thing->doStuff();
std::cout << std::endl;
delete thing;
}
} catch (int const & value) {
std::cout << "Caught a " << value
<< " ... wow this is evil!" << std::endl;
}
}
(Live on ideone)
The initialization of that "map" could probably made constexpr.
Of course instead of raw pointers (Thing *) you should use managed pointers (like std::unique_ptr). Further, if you don't want to have your processing (doStuff) as member functions, then just make a single "dispatching" (virtual) member function that calls out to a given function object, passing the own instance (this). With a CRTP base class, you don't need to implement that member function for every one of your types.
You're using something that may be called static (=compile-time) polymorphism. This requires to make such switch statements in order to convert the run-time value pHrd->dtype to one of the compile-time values handles in the case clauses. Something like your
process(multi_cast<pHdr->type>(pv);
is impossible, since pHdr->type is not known at compile time.
If you want to avoid the switch, you can use ordinary dynamic polymorphism and forget about the enum Hdr, but use a abstract base class
struct Base {
virtual void process()=0;
virtual ~Base() {}
};
struct Foo : Base { /* ... */ };
struct Bar : Base { /* ... */ };
Base*ptr = getData();
ptr->process();
I'm trying to create an easy way to register all my Project Euler solutions into a std::map in a factory pattern, in order to be able to refer to them in code by number. I found a fantastic answer on this site (Dynamically register constructor methods in an AbstractFactory at compile time using C++ templates) and came up with this solution:
EulerProblem.h:
#ifndef EULERPROBLEM_H
#define EULERPROBLEM_H
#include<string>
#include<sstream>
#include<QObject>
#include<QString>
// BASE PROBLEM CLASS
class EulerProblem : public QObject
{
Q_OBJECT
signals:
void printSignal(QString str);
void debugSignal(QString str);
void problemTextSignal(QString str);
protected:
EulerProblem() {}
void print(QString str);
void debug(QString str);
void setProblemText(QString str);
protected:
int problemNumber;
QString problemText;
public:
virtual ~EulerProblem() { }
void initialize();
virtual void doProblem() = 0;
};
// PROBLEM TEMPLATE, DERIVE PROBLEMS FROM THIS
template<int NUM, typename IMPL>
class ProblemTmpl : public EulerProblem
{
enum { _PROBLEM_ID = NUM };
public:
static EulerProblem* Create() { return new IMPL(); }
static const uint16_t PROBLEM_ID; // for registration
// static void Enable() { volatile uint16_t x = PROBLEM_ID; }
protected:
ProblemTmpl() { problemNumber = PROBLEM_ID; } //use parameter to instantiate template
};
// PROBLEM FACTORY, USE THIS TO GET PROBLEMS
class ProblemFactory
{
public:
typedef EulerProblem* (*t_pfFactory)();
static ProblemFactory *getInstance()
{
static ProblemFactory fact;
return &fact;
}
uint16_t Register(uint16_t msgid, t_pfFactory factoryMethod)
{
printf("Registering constructor for msg id %d\n", msgid);
m_List[msgid] = factoryMethod;
return msgid;
}
EulerProblem *Create(uint16_t msgid)
{
return m_List[msgid]();
}
std::map<uint16_t, t_pfFactory> m_List;
private:
ProblemFactory() {};
ProblemFactory(ProblemFactory const&) {};
ProblemFactory& operator=(ProblemFactory const&);
~ProblemFactory() {};
};
#endif // EULERPROBLEM_H
EulerProblem.cpp (note the first line, which is intended to automatically call Register()):
#include "eulerproblem.h"
template <int TYPE, typename IMPL>
const uint16_t ProblemTmpl<TYPE, IMPL>::PROBLEM_ID =
ProblemFactory::getInstance()->Register(ProblemTmpl<TYPE, IMPL>::_PROBLEM_ID, &ProblemTmpl<TYPE, IMPL>::Create);
void EulerProblem::initialize()
{
setProblemText(problemText);
}
void EulerProblem::debug(QString str)
{
emit debugSignal(str);
}
void EulerProblem::print(QString str)
{
emit printSignal(str);
}
void EulerProblem::setProblemText(QString str)
{
emit problemTextSignal(str);
}
Example problem class (049.h):
#ifndef _49_h
#define _49_h
class Problem049 : public ProblemTmpl<49, Problem049>
{
public:
Problem049()
{
problemText =
"The arithmetic sequence, 1487, 4817, 8147, in which each of the terms increases by 3330, is unusual in two ways: (i) each of the three terms are prime, and, (ii) each of the 4-digit numbers are permutations of one another.\n"
"\n"
"There are no arithmetic sequences made up of three 1-, 2-, or 3-digit primes, exhibiting this property, but there is one other 4-digit increasing sequence.\n"
"\n"
"What 12-digit number do you form by concatenating the three terms in this sequence?";
}
void doProblem()
{
// problem solution here
}
};
#endif /* _49_h */
So when I use the following code (the connect() calls are Qt stuff for wiring up signals):
ep = ProblemFactory::getInstance()->Create(49);
connect(ep, SIGNAL(printSignal(QString)), this, SLOT(addOutput(QString)));
connect(ep, SIGNAL(debugSignal(QString)), this, SLOT(addDebug(QString)));
connect(ep, SIGNAL(problemTextSignal(QString)), this, SLOT(setProblem(QString)));
ep->initialize();
I get a segfault from ProblemFactory::Create() because the std::map is empty--Register() was never called. The code compiles fine, however. Can anyone see what I'm doing wrong here? I've been hunting for a while.
I ran and compiled the example given as an answer in the other question, and it works fine. It's not something conflicting with Qt, is it?
Figured it out, though I don't understand why the solution worked.
I moved the following line:
template <int TYPE, typename IMPL>
const uint16_t ProblemTmpl<TYPE, IMPL>::PROBLEM_ID =
ProblemFactory::getInstance()->Register(ProblemTmpl<TYPE, IMPL>::_PROBLEM_ID, &ProblemTmpl<TYPE, IMPL>::Create);
From the top of EulerProblem.cpp to the bottom of EulerProblem.h and it worked. Does anyone have any insight as to why that is?
With the changes made in C++11 (such as the inclusion of std::bind), is there a recommended way to implement a simple single-threaded observer pattern without dependence on anything external to the core language or standard library (like boost::signal)?
EDIT
If someone could post some code showing how dependence on boost::signal could be reduced using new language features, that would still be very useful.
I think that bind makes it easier to create slots (cfr. the 'preferred' syntax vs. the 'portable' syntax - that's all going away). The observer management, however, is not becoming less complex.
But as #R. Martinho Fernandes mentions: an std::vector<std::function< r(a1) > > is now easily created without the hassle for an (artificial) 'pure virtual' interface class.
Upon request: an idea on connection management - probably full of bugs, but you'll get the idea:
// note that the Func parameter is something
// like std::function< void(int,int) > or whatever, greatly simplified
// by the C++11 standard
template<typename Func>
struct signal {
typedef int Key; //
Key nextKey;
std::map<Key,Func> connections;
// note that connection management is the same in C++03 or C++11
// (until a better idea arises)
template<typename FuncLike>
Key connect( FuncLike f ) {
Key k=nextKey++;
connections[k]=f;
return k;
}
void disconnect(Key k){
connections.erase(k);
}
// note: variadic template syntax to be reviewed
// (not the main focus of this post)
template<typename Args...>
typename Func::return_value call(Args... args){
// supposing no subcription changes within call:
for(auto &connection: connections){
(*connection.second)(std::forward(...args));
}
}
};
Usage:
signal<function<void(int,int)>> xychanged;
void dump(int x, int y) { cout << x << ", " << y << endl; }
struct XY { int x, y; } xy;
auto dumpkey=xychanged.connect(dump);
auto lambdakey=xychanged.connect([&xy](int x, int y){ xy.x=x; xy.y=y; });
xychanged.call(1,2);
Since you're asking for code, my blog entry Performance of a C++11 Signal System contains a single-file implementation of a fully functional signal system based on C++11 features without further dependencies (albeit single-threaded, which was a performance requirement).
Here is a brief usage example:
Signal<void (std::string, int)> sig2;
sig2() += [] (std::string msg, int d) { /* handler logic */ };
sig2.emit ("string arg", 17);
More examples can be found in this unit test.
I wrote my own light weight Signal/Slot classes which return connection handles. The existing answer's key system is pretty fragile in the face of exceptions. You have to be exceptionally careful about deleting things with an explicit call. I much prefer using RAII for open/close pairs.
One notable lack of support in my library is the ability to get a return value from your calls. I believe boost::signal has methods of calculating the aggregate return values. In practice usually you don't need this and I just find it cluttering, but I may come up with such a return method for fun as an exercise in the future.
One cool thing about my classes is the Slot and SlotRegister classes. SlotRegister provides a public interface which you can safely link to a private Slot. This protects against external objects calling your observer methods. It's simple, but nice encapsulation.
I do not believe my code is thread safe, however.
//"MIT License + do not delete this comment" - M2tM : http://michaelhamilton.com
#ifndef __MV_SIGNAL_H__
#define __MV_SIGNAL_H__
#include <memory>
#include <utility>
#include <functional>
#include <vector>
#include <set>
#include "Utility/scopeGuard.hpp"
namespace MV {
template <typename T>
class Signal {
public:
typedef std::function<T> FunctionType;
typedef std::shared_ptr<Signal<T>> SharedType;
static std::shared_ptr< Signal<T> > make(std::function<T> a_callback){
return std::shared_ptr< Signal<T> >(new Signal<T>(a_callback, ++uniqueId));
}
template <class ...Arg>
void notify(Arg... a_parameters){
if(!isBlocked){
callback(std::forward<Arg>(a_parameters)...);
}
}
template <class ...Arg>
void operator()(Arg... a_parameters){
if(!isBlocked){
callback(std::forward<Arg>(a_parameters)...);
}
}
void block(){
isBlocked = true;
}
void unblock(){
isBlocked = false;
}
bool blocked() const{
return isBlocked;
}
//For sorting and comparison (removal/avoiding duplicates)
bool operator<(const Signal<T>& a_rhs){
return id < a_rhs.id;
}
bool operator>(const Signal<T>& a_rhs){
return id > a_rhs.id;
}
bool operator==(const Signal<T>& a_rhs){
return id == a_rhs.id;
}
bool operator!=(const Signal<T>& a_rhs){
return id != a_rhs.id;
}
private:
Signal(std::function<T> a_callback, long long a_id):
id(a_id),
callback(a_callback),
isBlocked(false){
}
bool isBlocked;
std::function< T > callback;
long long id;
static long long uniqueId;
};
template <typename T>
long long Signal<T>::uniqueId = 0;
template <typename T>
class Slot {
public:
typedef std::function<T> FunctionType;
typedef Signal<T> SignalType;
typedef std::shared_ptr<Signal<T>> SharedSignalType;
//No protection against duplicates.
std::shared_ptr<Signal<T>> connect(std::function<T> a_callback){
if(observerLimit == std::numeric_limits<size_t>::max() || cullDeadObservers() < observerLimit){
auto signal = Signal<T>::make(a_callback);
observers.insert(signal);
return signal;
} else{
return nullptr;
}
}
//Duplicate Signals will not be added. If std::function ever becomes comparable this can all be much safer.
bool connect(std::shared_ptr<Signal<T>> a_value){
if(observerLimit == std::numeric_limits<size_t>::max() || cullDeadObservers() < observerLimit){
observers.insert(a_value);
return true;
}else{
return false;
}
}
void disconnect(std::shared_ptr<Signal<T>> a_value){
if(!inCall){
observers.erase(a_value);
} else{
disconnectQueue.push_back(a_value);
}
}
template <typename ...Arg>
void operator()(Arg... a_parameters){
inCall = true;
SCOPE_EXIT{
inCall = false;
for(auto& i : disconnectQueue){
observers.erase(i);
}
disconnectQueue.clear();
};
for (auto i = observers.begin(); i != observers.end();) {
if (i->expired()) {
observers.erase(i++);
} else {
auto next = i;
++next;
i->lock()->notify(std::forward<Arg>(a_parameters)...);
i = next;
}
}
}
void setObserverLimit(size_t a_newLimit){
observerLimit = a_newLimit;
}
void clearObserverLimit(){
observerLimit = std::numeric_limits<size_t>::max();
}
int getObserverLimit(){
return observerLimit;
}
size_t cullDeadObservers(){
for(auto i = observers.begin(); i != observers.end();) {
if(i->expired()) {
observers.erase(i++);
}
}
return observers.size();
}
private:
std::set< std::weak_ptr< Signal<T> >, std::owner_less<std::weak_ptr<Signal<T>>> > observers;
size_t observerLimit = std::numeric_limits<size_t>::max();
bool inCall = false;
std::vector< std::shared_ptr<Signal<T>> > disconnectQueue;
};
//Can be used as a public SlotRegister member for connecting slots to a private Slot member.
//In this way you won't have to write forwarding connect/disconnect boilerplate for your classes.
template <typename T>
class SlotRegister {
public:
typedef std::function<T> FunctionType;
typedef Signal<T> SignalType;
typedef std::shared_ptr<Signal<T>> SharedSignalType;
SlotRegister(Slot<T> &a_slot) :
slot(a_slot){
}
//no protection against duplicates
std::shared_ptr<Signal<T>> connect(std::function<T> a_callback){
return slot.connect(a_callback);
}
//duplicate shared_ptr's will not be added
bool connect(std::shared_ptr<Signal<T>> a_value){
return slot.connect(a_value);
}
void disconnect(std::shared_ptr<Signal<T>> a_value){
slot.disconnect(a_value);
}
private:
Slot<T> &slot;
};
}
#endif
Supplimental scopeGuard.hpp:
#ifndef _MV_SCOPEGUARD_H_
#define _MV_SCOPEGUARD_H_
//Lifted from Alexandrescu's ScopeGuard11 talk.
namespace MV {
template <typename Fun>
class ScopeGuard {
Fun f_;
bool active_;
public:
ScopeGuard(Fun f)
: f_(std::move(f))
, active_(true) {
}
~ScopeGuard() { if(active_) f_(); }
void dismiss() { active_ = false; }
ScopeGuard() = delete;
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard(ScopeGuard&& rhs)
: f_(std::move(rhs.f_))
, active_(rhs.active_) {
rhs.dismiss();
}
};
template<typename Fun>
ScopeGuard<Fun> scopeGuard(Fun f){
return ScopeGuard<Fun>(std::move(f));
}
namespace ScopeMacroSupport {
enum class ScopeGuardOnExit {};
template <typename Fun>
MV::ScopeGuard<Fun> operator+(ScopeGuardOnExit, Fun&& fn) {
return MV::ScopeGuard<Fun>(std::forward<Fun>(fn));
}
}
#define SCOPE_EXIT \
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
= MV::ScopeMacroSupport::ScopeGuardOnExit() + [&]()
#define CONCATENATE_IMPL(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
#ifdef __COUNTER__
#define ANONYMOUS_VARIABLE(str) \
CONCATENATE(str, __COUNTER__)
#else
#define ANONYMOUS_VARIABLE(str) \
CONCATENATE(str, __LINE__)
#endif
}
#endif
An example application making use of my library:
#include <iostream>
#include <string>
#include "signal.hpp"
class Observed {
private:
//Note: This is private to ensure not just anyone can spawn a signal
MV::Slot<void (int)> onChangeSlot;
public:
typedef MV::Slot<void (int)>::SharedSignalType ChangeEventSignal;
//SlotRegister is public, users can hook up signals to onChange with this value.
MV::SlotRegister<void (int)> onChange;
Observed():
onChange(onChangeSlot){ //Here is where the binding occurs
}
void change(int newValue){
onChangeSlot(newValue);
}
};
class Observer{
public:
Observer(std::string a_name, Observed &a_observed){
connection = a_observed.onChange.connect([=](int value){
std::cout << a_name << " caught changed value: " << value << std::endl;
});
}
private:
Observed::ChangeEventSignal connection;
};
int main(){
Observed observed;
Observer observer1("o[1]", observed);
{
Observer observer2("o[2]", observed);
observed.change(1);
}
observed.change(2);
}
Output of the above would be:
o[1] caught changed value: 1
o[2] caught changed value: 1
o[1] caught changed value: 2
As you can see, the slot disconnects dead signals automatically.
Here's what I came up with.
This assumes no need to aggregate results from the listeners of a broadcast signal.
Also, the "slot" or Signal::Listener is the owner of the callback.
This ought to live with the object that your (I'm guessing...) lambda is probably capturing so that when that object goes out of scope, so does the callback, which prevents it from being called anymore.
You could use methods described in other answers as well to store the Listener owner objects in a way you can lookup.
template <typename... FuncArgs>
class Signal
{
using fp = std::function<void(FuncArgs...)>;
std::forward_list<std::weak_ptr<fp> > registeredListeners;
public:
using Listener = std::shared_ptr<fp>;
Listener add(const std::function<void(FuncArgs...)> &cb) {
// passing by address, until copy is made in the Listener as owner.
Listener result(std::make_shared<fp>(cb));
registeredListeners.push_front(result);
return result;
}
void raise(FuncArgs... args) {
registeredListeners.remove_if([&args...](std::weak_ptr<fp> e) -> bool {
if (auto f = e.lock()) {
(*f)(args...);
return false;
}
return true;
});
}
};
usage
Signal<int> bloopChanged;
// ...
Signal<int>::Listener bloopResponse = bloopChanged.add([](int i) { ... });
// or
decltype(bloopChanged)::Listener bloopResponse = ...
// let bloopResponse go out of scope.
// or re-assign it
// or reset the shared_ptr to disconnect it
bloopResponse.reset();
I have made a gist for this too, with a more in-depth example:
https://gist.github.com/johnb003/dbc4a69af8ea8f4771666ce2e383047d
I have had a go at this myself also. My efforts can be found at this gist, which will continue to evolve . . .
https://gist.github.com/4172757
I use a different style, more similar to the change notifications in JUCE than BOOST signals. Connection management is done using some lambda syntax that does some capture by copy. It is working well so far.
Often I write classes like this:
Logger::Logger(bool log_time_, bool log_percentage, bool log_size):log_time(log_time_)... //made up example
Logger::Log()
{
string log_line;
if (log_time)
log_line += (get_time());
if (log_percentage)
log_line += (get_percentage());
//...
}
And I wonder is there a way to turn my class using template magic into a code that does the "if (something)" part at compile time.
EDIT:
Values of bool variables are known at compile time.
Preface
Two solutions will be found in this post, one using C++03 and the other C++11.
It's hard (ie. you'll need to write a lot of code) if you'd like a true compile time if that is guaranteed not to have any runtime overhead what so ever (no function jumps, etc etc).
It is however possible, though the code will be quite tedious to maintain if you feel like adding another option to it (in C++03). I'd recommend you to check out the below solutions.
Solution in C++03
Your compiler should be smart enough to optimize away any call to LogHelper<+NONE>, though if you are just looking for more readable code and not a superb performance gain this syntax is quite sweet.
enum LoggerType {
NONE =0,
DATE = (1<<0),
TIME = (1<<1),
PERCENT = (1<<2)
};
template<int> void LogHelper (std::string&);
template<> inline void LogHelper<+NONE> (std::string&) {}
template<> inline void LogHelper<+DATE> (std::string& s) {s += "1970-01-01 ";}
template<> inline void LogHelper<+TIME> (std::string& s) {s += "12:01:01 ";}
template<> inline void LogHelper<+PERCENT> (std::string& s) {s += "42% ";}
template<int LOG_FLAG = NONE>
struct Logger {
static void log (std::string const& description) {
std::string s1;
LogHelper<DATE & LOG_FLAG> (s1);
LogHelper<TIME & LOG_FLAG> (s1);
LogHelper<PERCENT & LOG_FLAG> (s1);
std::cerr.width (25);
std::cerr << s1 << " >> " << description << std::endl;
}
};
...
int
main (int argc, char * argv[]) {
Logger<DATE|TIME|PERCENT> foo_log;
Logger<TIME> time_log;
Logger<> no_log;
time_log.log ("log objects initialized!");
foo_log .log ("using foo_log");
no_log .log ("about to terminate application");
}
output
12:01:01 >> log objects initialized!
1970-01-01 12:01:01 42% >> using foo_log
>> about to terminate application
Solution using Variadic Templates (C++11)
enum LoggerType {
NONE, PERCENT, DATE, TIME
};
template<LoggerType T = NONE, LoggerType ... Next>
std::string LogHelper () {
return LogHelper<T> () + "; " + LogHelper<Next...> ();
}
template<> std::string LogHelper<NONE> () {return ""; }
template<> std::string LogHelper<DATE> () {return "1970-01-01";}
template<> std::string LogHelper<TIME> () {return "00:01:42";}
template<> std::string LogHelper<PERCENT> () {return "42%";}
template<LoggerType ... Types>
struct Logger {
static void log (std::string const& description) {
std::cerr.width (25);
std::cerr << LogHelper<Types...> ();
std::cerr << " >> " << description;
std::cerr << std::endl;
}
};
...
int
main (int argc, char * argv[]) {
Logger<DATE,TIME,PERCENT> foo_log;
Logger<TIME> time_log;
Logger<> no_log;
time_log.log ("log objects initialized!");
foo_log .log ("using foo_log");
no_log .log ("about to terminate application");
}
output
00:01:42 >> log objects initialized!
1970-01-01; 00:01:42; 42% >> using foo_log
>> about to terminate application
Yes this is possible, although some compilers will not like for you it. You will essentially however end up with a set of different classes as you have to provide booleans as the template specifiers (may not be the correct terminology).
I think you maybe better off using a virtual Log method instead? Then create a handful of classes which each define their own Log method. Unless you have some other reason I would suggest using virtual functions over templates for this case.
Sure. Something like this:
template <bool Opt1, bool Opt2> void foo()
{
Action1<Opt1>();
Action2<Opt2>();
}
template <bool> void Action1();
template <bool> void Action2();
template <> void Action1<true>() { /* ... */ }
template <> void Action1<false>() { /* ... */ }
template <> void Action2<true>() { /* ... */ }
template <> void Action2<false>() { /* ... */ }
Invoke this like foo<true, false>();.
Why would you want to employ templates where it isn't needed? Any self-respecting C++ compiler will do constant folding based on constant expressions: it has to work out the values for these at compile-time anyway. That is, any conditional based on a constant expression won't be there at run-time. The only two drawbacks of this approach are:
you are relying on the compiler to be reasonably decent at a rather basic level
symbols referenced from the code never executed my still be referenced
With respect to your Boolean flags you still have to make sure that they are recognized as constant expressions, however. Using a template would enforce this.
You can do something like this
struct DummyEnhancer
{
void operator()(string& s) const{
}
};
struct TimerEnhancer
{
void operator()(string& s) const{
s += "time";
}
};
struct PercenterEnhancer
{
void operator()(string& s) const{
s += "percent";
}
};
template <typename Timer , typename Percenter>
struct Logger
{
void Log()
{
string log_line;
Timer t;
t( log_line );
Percenter p;
p( log_line );
}
};
int main()
{
Logger<DummyEnhancer,DummyEnhancer> foo;
foo.Log();
Logger< TimerEnhancer , PercenterEnhancer > bar;
bar.Log();
return 0;
}
foo.Log() will be a no op and bar.log() will do both the timer and percentage stuff you want
Yes for compile time constants you can use template programming:
template<bool log_time, bool log_perchentage, bool log_size>
struct Logger
{
static void log()
{ // log everything
string log_line;
log_line+=(get_time());
log_line+=(get_perchentage());
log_line+=(get_size());
}
};
template<>
struct Logger<false, false, false>
{
static void log()
{ // nothing to log
}
};
You can also specialize the intermediate versions as Logger<true, false, false> and Logger<false, true, true> and so on. The other way to avoid several specializations is to separate time / percentage / size into different structs and log them separately.