I have spent the last few days trying to create a generalised wrapper of sorts for function pointers in C++ and I've managed to solve nearly every single issue bar one. My main goal with this was to be able to simply call an object as a function with a function pointer stored internally. If the pointer was pointing somewhere then it would call it as normal while a null pointer would just not call the function and it would continue on as if nothing happened. I intend to use this primarily for callback function purposes, where I would likely not care if the function was called or not and just wanted to preform an action. It works almost perfectly with the following:
template<typename T>
class Action;
template<typename TReturn, typename ... TArgs>
class Action<TReturn(TArgs...)> {
public:
//! Define a type for the Action object
typedef TReturn(*signature)(TArgs...);
//! Constructors
inline Action(const signature& pFunc = nullptr) : mPointer(pFunc) {}
inline Action(const Action& pCopy) : mPointer(pCopy.mPointer) {}
//! Operator Call
inline bool operator() (TReturn& pReturn, TArgs ... pArgs) const { if (!mPointer) return false; pReturn = mPointer(pArgs...); return true; }
//! Operators
inline Action& operator=(const Action& pCopy) { mPointer = pCopy.mPointer; return *this; }
inline Action& operator=(const signature& pFunc) { mPointer = pFunc; return *this; }
inline operator bool() const { return (mPointer != nullptr); }
private:
//! Store a pointer to the callback function
signature mPointer;
};
template<typename ... TArgs>
class Action<void(TArgs...)> {
public:
//! Define a type for the Action object
typedef void(*signature)(TArgs...);
//! Constructors
inline Action(const signature& pFunc = nullptr) : mPointer(pFunc) {}
inline Action(const Action& pCopy) : mPointer(pCopy.mPointer) {}
//! Operator Call
inline bool operator() (TArgs ... pArgs) const { if (!mPointer) return false; mPointer(pArgs...); return true; }
//! Operators
inline Action& operator=(const Action& pCopy) { mPointer = pCopy.mPointer; return *this; }
inline Action& operator=(const signature& pFunc) { mPointer = pFunc; return *this; }
inline operator bool() const { return (mPointer != nullptr); }
private:
//! Store a pointer to the callback function
signature mPointer;
};
However, I feel like the situation that would most likely use this wrapper is the output of debug information or formatted text. This could be through user defined functions or inbuilt functions such as printf. To match with printf's signature an Action would be created like:
Action<int(const char*, ...)> callback = printf;
and it would be able to operate the same way that any other Action would behave. The problem I'm finding is the '...' will force the template signature to not align with either of the specialisations, instead going with the first which is only a prototype.
I can fully understand why this doesn't work and why the compiler would not be able to handle the generation of the required class but I was hoping that someone here would know any sneaky ways to either achieve this or something similar. Any help would be much appreciated, thanks :)
The following example works for all function types, and lambdas with no capture:
#include <utility>
#include <cstdio>
#include <cmath>
template<typename Fn>
class Action {
Fn* function_ptr;
public:
Action() noexcept : function_ptr(nullptr) {}
Action(std::nullptr_t) noexcept : function_ptr(nullptr) {}
Action(const Action& other) : function_ptr(other.function_ptr) {}
Action(Fn f) : function_ptr(f) {}
Action& operator=(const Action& other) {
return (function_ptr = other.function_ptr, *this);
}
Action& operator=(std::nullptr_t ) {
return (function_ptr = nullptr, *this);
}
Action& operator=(Fn f) {
return (function_ptr = f, *this);
}
template<typename... Params>
auto operator()(Params&&... params) {
return function_ptr(std::forward<Params>(params)...);
}
};
Live Demo
As the comments under your question mention, using std::function is better than writing a wrapper for function pointers. The only problem with std::function is that it cannot be used with function signatures that contain ellipsis. If you explicitly specify the signature you can store e.g. printf as follows:
std::function<int(const char*, int, double, double)> fn = printf;
If you use C++17 or Boost, you can implement you own printf-like function, using std::any or Boost.Any which can be assigned to std::function as follows:
#include <iostream>
#include <string>
#include <vector>
#include <any>
#include <functional>
using namespace std;
void any_printf(string&& format, vector<any>&& args) {
int arg_index = 0; enum { NORMAL, CONVERT } mode;
for(auto& chr : format) {
if(mode == CONVERT) {
switch(chr) {
case 'd': cout << any_cast<int>(args[arg_index++]); break;
case 'f': cout << any_cast<float>(args[arg_index++]); break;
case 's': cout << any_cast<string>(args[arg_index++]); break;
/* ... */
default: cout << chr;
};
mode = NORMAL;
}
else {
chr == '%' ? (mode = CONVERT, 0) : (cout << chr, 0);
}
}
}
int main() {
using namespace string_literals;
function<void(string&&, vector<any>&&)> f_ptr { any_printf };
f_ptr("Cuboid: %smm x %dmm x %fmm.\n", { any("3"s), any(4), any(6.67f) });
return 0;
}
Related
I created sets of functions using the type-erasure design pattern:
Encodable: encode(), decode()
Printable: print()
If I overload these functions with MyStruct1 and MyStruct2, I'll be able to wrap these types in the type-erasure wrappers Encodable and Printable and indirectly call those functions using the wrappers functions and store MyStruct1 and MyStruct2 in a heterogeneous container like std::vector<Encodable>.
My problem arised when I wanted to use these objects both as an Encodable and a Printable or when I wanted to convert one to the other.
#include <cstdint>
#include <utility>
#include <memory>
#include <vector>
class Encodable {
private:
struct EncodableConcept {
virtual ~EncodableConcept() = default;
virtual std::vector<uint8_t> _encode() const = 0;
virtual bool _decode(std::vector<uint8_t> const& byteVector) = 0;
virtual std::unique_ptr<EncodableConcept> clone() const = 0;
};
template<typename EncodableT>
struct EncodableModel : public EncodableConcept {
EncodableModel(EncodableT inst) : _inst{std::move(inst)}
{}
std::vector<uint8_t> _encode() const override {
return encode(_inst);
}
bool _decode(std::vector<uint8_t> const& byteVector) override {
return decode(_inst, byteVector);
}
std::unique_ptr<EncodableConcept> clone() const override {
return std::make_unique<EncodableModel>(*this);
}
EncodableT _inst;
};
friend std::vector<uint8_t> encode(Encodable const& inst) {
return inst.pimpl->_encode();
}
friend bool decode(Encodable & inst, std::vector<uint8_t> const& byteVector) {
return inst.pimpl->_decode(byteVector);
}
public:
template<typename EncodableT>
Encodable(EncodableT inst)
: pimpl{std::make_unique<EncodableModel<EncodableT>>(std::move(inst))}
{}
Encodable(Encodable const& other)
: pimpl(other.pimpl->clone())
{}
Encodable& operator=(Encodable const& other) {
// Copy-and-swap idiom
Encodable tmp(other);
std::swap(pimpl, tmp.pimpl);
return *this;
}
// Move is not implemented to prevent the pimpl to be nullptr after move operation.
// Upon move the copy constructor or the copy assignment operator is going to be called.
private:
std::unique_ptr<EncodableConcept> pimpl;
};
class Printable {
private:
struct PrintableConcept {
virtual ~PrintableConcept() = default;
virtual void _print() const = 0;
virtual std::unique_ptr<PrintableConcept> clone() const = 0;
};
template<typename PrintableT>
struct PrintableModel : public PrintableConcept {
PrintableModel(PrintableT inst) : _inst{std::move(inst)}
{}
void _print() const override {
print(_inst);
}
std::unique_ptr<PrintableConcept> clone() const override {
return std::make_unique<PrintableModel>(*this);
}
PrintableT _inst;
};
friend void print(Printable const& inst) {
inst.pimpl->_print();
}
public:
template<typename PrintableT>
Printable(PrintableT inst)
: pimpl{std::make_unique<PrintableModel<PrintableT>>(std::move(inst))}
{}
Printable(Printable const& other)
: pimpl(other.pimpl->clone())
{}
Printable& operator=(Printable const& other) {
// Copy-and-swap idiom
Printable tmp(other);
std::swap(pimpl, tmp.pimpl);
return *this;
}
// Move is not implemented to prevent the pimpl to be nullptr after move operation.
// Upon move the copy constructor or the copy assignment operator is going to be called.
private:
std::unique_ptr<PrintableConcept> pimpl;
};
struct MyStruct1 {
MyStruct1(int x) : x{x} {}
int x;
};
std::vector<uint8_t> encode(MyStruct1 const& inst) {
std::vector<uint8_t> byteVector;
// ...
return byteVector;
}
bool decode(MyStruct1 & inst, std::vector<uint8_t> const& byteVector) {
// ...
return true; // Success
}
void print(MyStruct1 const& inst) {
printf("MyStruct1{%d}\n", inst.x);
}
struct MyStruct2 {
MyStruct2(float y) : y{y} {}
float y;
};
std::vector<uint8_t> encode(MyStruct2 const& inst) {
std::vector<uint8_t> byteVector;
// ...
return byteVector;
}
bool decode(MyStruct2 & inst, std::vector<uint8_t> const& byteVector) {
// ...
return true; // Success
}
void print(MyStruct2 const& inst) {
printf("MyStruct2{%f}\n", inst.y);
}
std::vector<Encodable> readFromSomewhere() {
std::vector<Encodable> readEncodables;
// Read from file, socket, etc...
readEncodables = {MyStruct1{1}, MyStruct2{2.2}, MyStruct1{3}, MyStruct2{4.4}};
return readEncodables;
}
int main(int argc, char** argv) {
std::vector<Encodable> readEncodables = readFromSomewhere();
// TODO: How can I print readEncodables using the overloaded print functions?
// For example:
for (Encodable const& obj : readEncodables) {
// print(obj); // Compilation error (thanks god)
}
// TODO: How can I convert an Encodable to a Printable object?
std::vector<Printable> convertedPrintables;
for (Encodable const& obj : readEncodables) {
// convertedPrintables.emplace_back(obj); // Compilation error (thanks god)
// print(*convertedPrintables.crbegin());
}
return 0;
}
How can I easily convert an Encodable to a Printable and vice versa?
Can I somehow directly use an Encodable as a Printable if the print() function is overloaded for the given type?
My only (bad) solution is to create a templated get() function in the wrappers to unwrap the contained object run-time. If the type of the template argument matches the object the unwrap succeeds and I can rewrap it into a Printable or just directly use the overloaded print() free function.
template<typename EncodableT>
EncodableT* get() const {
EncodableModel<EncodableT>* modelPtr = dynamic_cast<EncodableModel<EncodableT>*> pimpl.get());
if (modelPtr == nullptr) return nullptr;
return &modelPtr->_inst;
}
However the usage of this function would be rather ugly and inconvenient:
for (Encodable const& obj : readEncodables) {
auto* ptr1 = obj.get<MyStruct1>();
if (ptr1 != nullptr) {
print(*ptr1);
continue;
}
auto* ptr2 = obj.get<MyStruct2>();
if (ptr2 != nullptr) {
print(*ptr2);
continue;
}
// ...
}
This could be made a bit nicer by storing std::type_index the wrappers, but I'd still have create if-else or switch statements for each type for calling a simple print() free function...
I have a particle class which keeps the position, velocity and the acceleration of an object. I can access the related part of the vector via .position(), .velocity() and .acceleration(). I also can access each single number like .velocity_x(), .velocity_y(), .velocity_z() etc. what I would like to do is to access the z part of velocity this way:
p.velocity().z()
I would like to use both .velocity() (as a subvector) and .velocity().z() (as a single number) at the same time.
I also would like to avoid defining any extra variable. I prefer everything be interpreted at the compile time (due to performance priority).
Is this implementation possible in c++?
In an attempt, I have considered returning another class with a functor. But beside the problem of compile time interpretation there is an issue with const as .velocity() does not know whether it will be followed by a const or non-const form of .z().
#include <iostream>
#include <armadillo>
class Particle
{
public:
arma::vec::fixed<9> data;
inline double velocity_z() const
{
return data(5);
}
inline double& velocity_z()
{
return data(5);
}
inline const arma::subview_col<double> position() const
{
return data.subvec(0,2);
}
inline arma::subview_col<double> position()
{
return data.subvec(0,2);
}
inline const arma::subview_col<double> velocity() const
{
return data.subvec(3,5);
}
inline arma::subview_col<double> velocity()
{
return data.subvec(3,5);
}
inline const arma::subview_col<double> acceleration() const
{
return data.subvec(6,8);
}
inline arma::subview_col<double> acceleration()
{
return data.subvec(6,8);
}
};
arma::vec vector3(double x,double y,double z)
{
return {x,y,z};
}
int main()
{
Particle p;
p.position()=vector3(1.1,2.1,3.1);
p.velocity()=vector3(1.2,2.2,3.2);
p.velocity_z()=10.0;
p.acceleration()=vector3(1.3,2.3,3.3);
p.data.print();
return 0;
}
// output:
// 1.1000
// 2.1000
// 3.1000
// 1.2000
// 2.2000
// 10.0000
// 1.3000
// 2.3000
// 3.3000
make:
g++ -std=c++11 test1.cpp -larmadillo
Armadillo documentation
Well, one possible solution would be to return a proxy object that both exposes the .{x|y|z}() member functions and is implicitly convertible to your vector type.
Conceptually like this:
#include <type_traits>
using vector_t = /* your library type */;
template<bool RValue>
class vector_proxy {
using return_type = typename std::conditional<RValue, vector_t&&, vector_t const&>::type;
vector_t &ref;
public:
vector_proxy(vector_t &ref) : ref(ref) {}
vector_proxy(vector_proxy const&) = delete;
vector_proxy& operator=(vector_proxy const&) = delete;
vector_proxy(vector_proxy&&) = delete;
vector_proxy& operator=(vector_proxy&&) = delete;
auto x() { /* code to produce x */ }
auto y() { /* code to produce y */ }
auto z() { /* code to produce z */ }
operator return_type() { return static_cast<return_type>(ref); }
};
Why a template? Because I would imagine you'd want different behavior, depending on the value category of the particle object.
We wouldn't want to return a non-const reference to a particles internal data if that particle is an lvalue. If it's an rvalue, we may as well return an rvalue reference as well so the code behaves "as expected".
The member function velocity() of the particle can have a value category qualifier to differentiate the two cases. And the template above just captures common behavior and abstracts the differences.
class particle {
// Members
public:
vector_proxy<false> velocity() const& { return {/* A ref to the velocity member */}; }
vector_proxy<true> velocity() && { return {/* A ref to the velocity member */}; }
// More functionality
};
Since you clarified in the comments that velocity always shuold returns a new vector object by value (an excellent default approach, btw), while allowing to modify the particle as well. The solution above needs to be updated:
class particle;
template<bool ByRef>
class vector_proxy {
using return_type =
typename std::conditional<ByRef, double&, double>::type;
using ref_type =
typename std::conditional<ByRef, particle&, particle const&>::type;
ref_type ref;
public:
vector_proxy(ref_type ref) : ref(ref) {}
vector_proxy(vector_proxy const&) = delete;
vector_proxy& operator=(vector_proxy const&) = delete;
vector_proxy(vector_proxy&&) = delete;
vector_proxy& operator=(vector_proxy&&) = delete;
return_type x();
return_type y();
return_type z();
operator vector_t();
};
class particle {
// Members
template<bool>
friend class vector_proxy;
public:
vector_proxy<false> velocity() const { return {*this}; }
vector_proxy<true> velocity() { return {*this}; }
// More functionality
};
template<bool ByRef>
auto vector_proxy<ByRef>::x -> return_type {
return ref.data(3);
}
template<bool ByRef>
auto vector_proxy<ByRef>::y -> return_type {
return ref.data(4);
}
template<bool ByRef>
auto vector_proxy<ByRef>::z -> return_type {
return ref.data(5);
}
template<bool ByRef>
vector_proxy<ByRef>::operator vector_t() {
return ref.data.subvec(3, 5)
}
And that should be it.
Here is the problem I was thinking about lately. Let's say our interface is a member function that returns object which is expensive to copy and cheap to move (std::string, std::vector, et cetera). Some implementations may compute the result and return a temporary object while others may simply return a member object.
Sample code to illustrate:
// assume the interface is: Vec foo() const
// Vec is cheap to move but expensive to copy
struct RetMember {
Vec foo() const { return m_data; }
Vec m_data;
// some other code
}
struct RetLocal {
Vec foo() const {
Vec local = /*some computation*/;
return local;
}
};
There are also various "clients". Some only read the data, some require an ownership.
void only_reads(const Vec&) { /* some code */ }
void requires_ownership(Vec) { /* some code */ }
Code above composes well, but is not as efficient as it could be. Here are all combinations:
RetMember retmem;
RetLocal retloc;
only_reads(retmem.foo()); // unnecessary copy, bad
only_reads(retloc.foo()); // no copy, good
requires_ownership(retmem.foo()); // copy, good
requires_ownership(retloc.foo()); // no copy, good
What is a good way to fix this situation?
I came up with two ways, but I'm sure there is a better solution.
In my first attempt I wrote a DelayedCopy wrapper that holds either a value of T or a pointer to const T. It is very ugly, requires extra effort, introduces redundant moves, gets in the way of copy elision and probably has many other problems.
My second thought was a continuation-passing style, which works quite well but turns member functions into member function templates. I know, there is std::function, but it has its overhead so performance-wise it may be unacceptable.
Sample code:
#include <boost/variant/variant.hpp>
#include <cstdio>
#include <iostream>
#include <type_traits>
struct Noisy {
Noisy() = default;
Noisy(const Noisy &) { std::puts("Noisy: copy ctor"); }
Noisy(Noisy &&) { std::puts("Noisy: move ctor"); }
Noisy &operator=(const Noisy &) {
std::puts("Noisy: copy assign");
return *this;
}
Noisy &operator=(Noisy &&) {
std::puts("Noisy: move assign");
return *this;
}
};
template <typename T> struct Borrowed {
explicit Borrowed(const T *ptr) : data_(ptr) {}
const T *get() const { return data_; }
private:
const T *data_;
};
template <typename T> struct DelayedCopy {
private:
using Ptr = Borrowed<T>;
boost::variant<Ptr, T> data_;
static_assert(std::is_move_constructible<T>::value, "");
static_assert(std::is_copy_constructible<T>::value, "");
public:
DelayedCopy() = delete;
DelayedCopy(const DelayedCopy &) = delete;
DelayedCopy &operator=(const DelayedCopy &) = delete;
DelayedCopy(DelayedCopy &&) = default;
DelayedCopy &operator=(DelayedCopy &&) = default;
DelayedCopy(T &&value) : data_(std::move(value)) {}
DelayedCopy(const T &cref) : data_(Borrowed<T>(&cref)) {}
const T &ref() const { return boost::apply_visitor(RefVisitor(), data_); }
friend T take_ownership(DelayedCopy &&cow) {
return boost::apply_visitor(TakeOwnershipVisitor(), cow.data_);
}
private:
struct RefVisitor : public boost::static_visitor<const T &> {
const T &operator()(Borrowed<T> ptr) const { return *ptr.get(); }
const T &operator()(const T &ref) const { return ref; }
};
struct TakeOwnershipVisitor : public boost::static_visitor<T> {
T operator()(Borrowed<T> ptr) const { return T(*ptr.get()); }
T operator()(T &ref) const { return T(std::move(ref)); }
};
};
struct Bar {
Noisy data_;
auto fl() -> DelayedCopy<Noisy> { return Noisy(); }
auto fm() -> DelayedCopy<Noisy> { return data_; }
template <typename Fn> void cpsl(Fn fn) { fn(Noisy()); }
template <typename Fn> void cpsm(Fn fn) { fn(data_); }
};
static void client_observes(const Noisy &) { std::puts(__func__); }
static void client_requires_ownership(Noisy) { std::puts(__func__); }
int main() {
Bar a;
std::puts("DelayedCopy:");
auto afl = a.fl();
auto afm = a.fm();
client_observes(afl.ref());
client_observes(afm.ref());
client_requires_ownership(take_ownership(a.fl()));
client_requires_ownership(take_ownership(a.fm()));
std::puts("\nCPS:");
a.cpsl(client_observes);
a.cpsm(client_observes);
a.cpsl(client_requires_ownership);
a.cpsm(client_requires_ownership);
}
Output:
DelayedCopy:
Noisy: move ctor
client_observes
client_observes
Noisy: move ctor
Noisy: move ctor
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
CPS:
client_observes
client_observes
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
Are there better techniques to pass values that avoid extra copies yet are still general (allow returning both temporaries and data members)?
On a side note: the code was compiled with g++ 5.2 and clang 3.7 in C++11. In C++14 and C++1z DelayedCopy doesn't compile and I'm not sure whether it's my fault or not.
There are probably thousands of 'correct' ways. I would favour one in which:
the the method that delivers the reference or moved object is explicitly stated so no-one is in any doubt.
as little code to maintain as possible.
all code combination compile and do sensible things.
something like this (contrived) example:
#include <iostream>
#include <string>
#include <boost/optional.hpp>
// an object that produces (for example) strings
struct universal_producer
{
void produce(std::string s)
{
_current = std::move(s);
// perhaps signal clients that there is something to take here?
}
// allows a consumer to see the string but does not relinquish ownership
const std::string& peek() const {
// will throw an exception if there is nothing to take
return _current.value();
}
// removes the string from the producer and hands it to the consumer
std::string take() // not const
{
std::string result = std::move(_current.value());
_current = boost::none;
return result;
}
boost::optional<std::string> _current;
};
using namespace std;
// prints a string by reference
void say_reference(const std::string& s)
{
cout << s << endl;
}
// prints a string after taking ownership or a copy depending on the call context
void say_copy(std::string s)
{
cout << s << endl;
}
auto main() -> int
{
universal_producer producer;
producer.produce("Hello, World!");
// print by reference
say_reference(producer.peek());
// print a copy but don't take ownership
say_copy(producer.peek());
// take ownership and print
say_copy(producer.take());
// producer now has no string. next peek or take will cause an exception
try {
say_reference(producer.peek());
}
catch(const std::exception& e)
{
cout << "exception: " << e.what() << endl;
}
return 0;
}
expected output:
Hello, World!
Hello, World!
Hello, World!
exception: Attempted to access the value of an uninitialized optional object.
I'm trying to store a set of std::function in a map (under GCC 4.5)
I'd like to get 2 kind of things :
storing functions with arguments already passed; then you just have
to call f()
storing functions without arguments; then you have to call
f(...)
I think I achieved the first one with a class Command and a Manager :
class Command
{
std::function<void()> f_;
public:
Command() {}
Command(std::function<void()> f) : f_(f) {}
void execute() { if(f_) f_(); }
};
class CommandManager
{
typedef map<string, Command*> FMap;
public :
void add(string name, Command* cmd)
{
fmap1.insert(pair<string, Command*>(name, cmd));
}
void execute(string name)
{
FMap::const_iterator it = fmap1.find(name);
if(it != fmap1.end())
{
Command* c = it->second;
c->execute();
}
}
private :
FMap fmap1;
};
can be used like this :
class Print{
public:
void print1(string s, string s1){ cout<<"print1 : "<<"s : "<<s<<" s1 : "<<s1<<endl; }
int print2(){ cout<<"print2"<<endl; return 2;}
};
#include <string>
#include <functional>
int main()
{
Print p = Print();
function<void()> f1(bind(&Print::print1, &p, string("test1"), string("test2")));
function<int()> f2(bind(&Print::print2, &p));
CommandManager cmdMgr = CommandManager();
cmdMgr.add("print1", new Command(f1));
cmdMgr.execute("print1");
cmdMgr.add("print2", new Command(f2));
cmdMgr.execute("print2");
return 0;
}
Now I'd like to be able to do this :
int main()
{
Print p = Print();
function<void(string, string)> f1(bind(&Print::print1, &p, placeholders::_1, placeholders::_2));
CommandManager cmdMgr = CommandManager();
cmdMgr.add("print1", new Command(f1));
cmdMgr.execute("print1", string("test1"), string("test2"));
return 0;
}
Is there a way, using type-erasure for example ?
You could use dynamic cast to determine the type of the function in the list at runtime.
Please note that I added shared_ptr to remove the memory leak in the original sample. Perhaps you want to throw a exception if the execute method is called with the wrong arguments (if the dynamic_cast yields 0).
Usage:
void x() {}
void y(int ) {}
void main() {
CommandManager m;
m.add("print", Command<>(x));
m.add("print1", Command<int>(y));
m.execute("print");
m.execute("print1", 1);
}
Code (with variadic template support for example gcc-4.5):
#include <functional>
#include <map>
#include <string>
#include <memory>
using namespace std;
class BaseCommand
{
public:
virtual ~BaseCommand() {}
};
template <class... ArgTypes>
class Command : public BaseCommand
{
typedef std::function<void(ArgTypes...)> FuncType;
FuncType f_;
public:
Command() {}
Command(FuncType f) : f_(f) {}
void operator()(ArgTypes... args) { if(f_) f_(args...); }
};
class CommandManager
{
typedef shared_ptr<BaseCommand> BaseCommandPtr;
typedef map<string, BaseCommandPtr> FMap;
public :
template <class T>
void add(string name, const T& cmd)
{
fmap1.insert(pair<string, BaseCommandPtr>(name, BaseCommandPtr(new T(cmd))));
}
template <class... ArgTypes>
void execute(string name, ArgTypes... args)
{
typedef Command<ArgTypes...> CommandType;
FMap::const_iterator it = fmap1.find(name);
if(it != fmap1.end())
{
CommandType* c = dynamic_cast<CommandType*>(it->second.get());
if(c)
{
(*c)(args...);
}
}
}
private :
FMap fmap1;
};
without variadic template support (example VS2010):
#include <functional>
#include <map>
#include <string>
#include <memory>
using namespace std;
class Ignored;
class BaseCommand
{
public:
virtual ~BaseCommand() = 0 {};
};
template <class A1 = Ignored>
class Command : public BaseCommand
{
typedef std::function<void(A1)> FuncType;
FuncType f_;
public:
Command() {}
Command(FuncType f) : f_(f) {}
void operator()(const A1& a1) { if(f_) f_(a1); }
};
template <>
class Command<Ignored> : public BaseCommand
{
typedef std::function<void()> FuncType;
FuncType f_;
public:
Command() {}
Command(FuncType f) : f_(f) {}
void operator()() { if(f_) f_(); }
};
class CommandManager
{
typedef shared_ptr<BaseCommand> BaseCommandPtr;
typedef map<string, BaseCommandPtr> FMap;
public :
template <class T>
void add(string name, const T& cmd)
{
fmap1.insert(pair<string, BaseCommandPtr>(name, BaseCommandPtr(new T(cmd))));
}
template <class A1>
void execute(string name, const A1& a1)
{
typedef Command<A1> CommandType;
FMap::const_iterator it = fmap1.find(name);
if(it != fmap1.end())
{
CommandType* c = dynamic_cast<CommandType*>(it->second.get());
if(c)
{
(*c)(a1);
}
}
}
void execute(string name)
{
typedef Command<> CommandType;
FMap::const_iterator it = fmap1.find(name);
if(it != fmap1.end())
{
CommandType* c = dynamic_cast<CommandType*>(it->second.get());
if(c)
{
(*c)();
}
}
}
private :
FMap fmap1;
};
What you are trying to do is not possible without some serious runtime work and the associated cost. The simplest solution would of course to just store a boost::any (any_function never made it into boost) inside your map and do the necessary casts (or add some runtime data that tells you which cast to make), although you should avoid that at any cost and go with fixed arguments or no arguments.
Your users can then modify their functions using bind to match the signature you require.
Edit: In your current scheme I see no reason for CommandManager to store Command* in the map.
Edit2: Also you drop the return type. This could be OK for your use-case but makes this a lot less generic.
Edit3: I worked out some working example of your code using any. I feel that there is some flaw and I really don't see what this should achieve but here it goes:
#include <iostream>
#include <string>
#include <map>
#include <functional>
#include <boost/any.hpp>
class AnyCaller
{
std::map<std::string, boost::any> calls;
public:
AnyCaller() {}
void add(const std::string& name, const boost::any& fun) {
calls[name] = fun;
}
// we always use the throwing version of any_cast
// icbb by error checking
// no arg version
template<typename Ret>
Ret call(const std::string& s) {
const boost::any& a = calls[s];
return boost::any_cast< std::function<Ret(void)> >(a)();
}
// this should be a variadic template to be actually usable
template<typename Ret, typename T>
Ret call(const std::string& s, T&& arg) {
// we have to assume that our users know what we are actually returning here
const boost::any& a = calls[s];
return boost::any_cast< std::function<Ret(T)> >(a)(std::forward<T>(arg));
}
virtual ~AnyCaller() {}
};
int foo() { std::cout << "foo" << std::endl; return 1; }
double foo2(int i) { std::cout << "foo2" << std::endl; return double(i); }
int main()
{
AnyCaller c;
c.add("foo", std::function<int(void)>(foo));
c.add("foo2", std::function<double(int)>(foo2));
c.call<int>("foo");
c.call<double, int>("foo2", 1);
// this should throw
c.call<double, int>("foo", 1);
return 0;
}
As for the example using a fixed signature. Just think of what would be the most natural representation of a function you are going to store (looking at your Command example I'd assume it is std::function<void(void)>. Store functions of this type and whenever one your users tries to use it, he has to bind whatever function he wants to use, so it matches this signature.
Your Command class constructor needs a function<void()>. You are trying to feed it a function<void(string,string)>. This is not going to typecheck.
If you need functions that accept variable arguments (like printf), you will need function<> and execute() that accept variable arguments. You need to know how to work with that (in particular, you need a fixed first argument). You are then responsible for type safety, much like with printf.
If you just need a variable number of string arguments, use functions that accept e.g. vectors of strings.
All this has nothing to do whatsoever with std::map. Whatever you can store in a plain old variable, you can store in std::map too.
First a disclaimer, I am replacing a bunch of code which uses boost::function and boost::bind. However, I am moving to a codebase which does not allow rtti. I would like to keep using boost but don't know if there is a way around this restriction.
So, I am trying to mimic some of its functionality, but much more simplified. I have a Callback class:
template <class Class, typename ReturnType = void> class Callback0 {
typedef ReturnType (Class::*Method)();
public:
Callback0(Class* object, Method method)
: m_object(object)
, m_method(method)
{
;
}
Callback0(const Callback0& callback)
: m_object(callback.m_object)
, m_method(callback.m_method)
{
;
}
operator bool() {
return m_object != 0;
}
operator bool() const {
return m_object != 0;
}
ReturnType operator()() {
return (m_object->*m_method)();
}
Callback0<Class, ReturnType>& operator=(const Callback0<Class, ReturnType>& callback) {
if(this != &callback) {
m_object = callback.m_object;
m_method = callback.m_method;
}
return *this;
}
private:
Class* m_object;
Method m_method;
};
This allows me to do simple callbacks with zero parameters:
class Meh {
public:
Meh() {;}
~Meh() {;}
void f0() {
footprint6v("%s\n", __FUNCTION__);
}
};
static void meh() {
Meh* m = new Meh;
Callback0<Meh, void> c0(m, &Meh::f0);
c0();
}
I would like to be able to assign my callback objects to zero as default parameters like so:
class Wtf {
public:
Wtf() : m_callback(0) {;}
~Wtf() {;}
void doSomething(const Callback0<Wtf, void>& callback = 0) {
m_callback = callback;
}
private:
Callback0<Wtf, void> m_callback;
};
This works when using boost::function as you can do:
class Wtf {
public:
Wtf() : m_callback(0) {;}
~Wtf() {;}
void doSomething(const boost::function<void()>& callback = 0) {
m_callback = callback;
}
private:
boost::function<void()> m_callback;
};
I imagine boost is doing some magic here. I know I can just change the parameter to a pointer rather than a reference but as I said, I am replacing a lot of code and would like to minimize the impact of changing from boost.
Boost isn't doing anything magic. 0 is just a NULL function pointer for the function pointer constructor.
I would suggest in your case you just provide a default constructor
Callback0() : m_object(NULL), m_method(NULL) {}
And make doSomething look like
void doSomething(const Callback0<Wtf, void>& callback = Callback0<Wtf, void>()) {