I have a std::map defined as follows:
typedef void (SomeClass::*callback_f)();
typedef std::pair<std::string, callback_f> my_pair;
typedef std::map<char,my_pair> my_map1;
There are multiple of these definitions, so there is my_map1, my_map2, etc. and every one of them differs from the other for the class SomeClass, which is SomeClass, SomeClassTwo, etc.
My need is to pass all these maps to a single function, which must have a single signature regardless of the maps, so I defined a generic map:
typedef std::pair<std::string ,void(*)(void)> my_generic_pair;
typedef std::map<char, my_generic_pair> my_generic_map;
And a function which takes it as a parameter:
void myGenericFunction(my_generic_map lmap);
myGenericFunction doesn't really use the callback, but uses the other two values from the my_map{$i}, i=1...n.
The problem is no matter how hard I try to cast between the two maps, the compiler (C++11 compliant GCC) always complains.
Any ideas would be very much appreciated.
If you need to pass all the maps to a single function, then all the maps must be exactly the same type (but you already knew that).
A little re-engineering should give you what you want.
Rather than define your map to hold a specific function pointer signature, simply define one map type that holds a polymorphic callable object - such an object is the std::function<>.
full compilable example (remember to enable c++11):
#include <iostream>
#include <functional>
#include <utility>
#include <string>
#include <map>
// callback_f is any callable that takes no parameters
typedef std::function<void()> callback_f;
typedef std::pair<std::string, callback_f> my_pair;
typedef std::map<char,my_pair> universal_map;
using namespace std;
struct SomeClass {
static void callme_for_all() {
cout << "SomeClass Hears You";
}
};
struct SomeOtherClass {
SomeOtherClass(string name)
: _name { move(name) }
{}
void callme_for_each() const {
cout << "I am called " << _name;
}
private:
string _name;
};
void handle_map(const universal_map& m) {
for (const auto& item : m) {
cout << item.first << ":" << item.second.first << ":";
item.second.second();
cout << endl;
}
}
int main()
{
cout << "Hello World" << endl;
SomeClass a,b,c;
SomeOtherClass x { "x" }, y { "y" }, z { "z" };
universal_map map_someclass {
{ 'A', { "chicken", std::bind(&SomeClass::callme_for_all) } },
{ 'B', { "donkey", std::bind(&SomeClass::callme_for_all) } },
{ 'C', { "turkey", std::bind(&SomeClass::callme_for_all) } },
};
universal_map map_someotherclass {
{ 'A', { "pig", std::bind(&SomeOtherClass::callme_for_each, &x) } },
{ 'B', { "cat", std::bind(&SomeOtherClass::callme_for_each, &y) } },
{ 'C', { "dog", std::bind(&SomeOtherClass::callme_for_each, &z) } },
};
cout << "map for SomeClass - calling static methods" << endl;
handle_map(map_someclass);
cout << endl;
cout << "map for SomeOtherClass - calling instance methods" << endl;
handle_map(map_someotherclass);
return 0;
}
If you have control on your SomeClass, SomeClass2..., you can use inheritance to solve this problem:
class BaseClass
{
public:
virtual ~BaseClass(){}
virtual void f() = 0;
};
class SomeClass : public BaseClass {...};
class SomeClass2 : public BaseClass {...};
typedef void (BaseClass::*callback_f)();
....
Solution 1:
template<typename T>
void myGenericFunction(std::map < char, std::pair < std::string, T > > lmap);
Solution 2 (only if you can't use templates and overloading for whatever reason):
enum MapType {MY_MAP1, MY_MAP2, ...};
void myGenericFunction(void* lmap, MapType typeOfLmap)
{
switch(typeOfLmap)
{
case MY_MAP1:
//do something with ((my_map1*)lmap)
break;
...
}
}
EDIT: edited according to #TonyD's suggestion.
Related
I get the Erro:
"no instance of constructor "std::vector<_Ty, _Alloc>::vector
[with _Ty=FunctionToUpdate, _Alloc=std::allocator<FunctionToUpdate>]" matches the argument list"
No matter how I change it, it persists, as long I keep it as a class. If I keep it all in just a simple .cpp without class and header, it all resolves easily.
My.h:
#include <vector>
#include <functional>
#include <iostream>
struct Params
{
std::vector<int> Integers;
std::vector<std::string> Strings;
};
struct FunctionToUpdate
{
int Version;
std::function<void(int, Params)> Function;
Params Parameters;
};
class Error
{
public:
Error();
void testFunctionA(int a, Params p);
void testFunctionB(int a, Params p);
protected:
const static std::vector<FunctionToUpdate> table;
};
Here is my .cpp, please assist me, I can't find the error:
#include "ErrorHandling.h"
Error::Error()
{
for (auto functionToUpdate : table)
{
functionToUpdate.Function(functionToUpdate.Version, functionToUpdate.Parameters);
std::cout << "############################################" << std::endl;
}
std::cout << "Done!" << std::endl;
}
void Error::testFunctionA(int a, Params parameter)
{
//std::cout << "Size Integers: " << parameter.Integers.size() << std::endl;
//std::cout << "Size Strings: " << parameter.Strings.size() << std::endl;
std::cout << a << std::endl;
for (auto& integer : parameter.Integers)
{
std::cout << integer << std::endl;
}
for (auto& integer : parameter.Strings)
{
std::cout << integer << std::endl;
}
}
void Error::testFunctionB(int a, Params parameter)
{
std::cout << a << std::endl;
std::cout << parameter.Integers.at(0) << std::endl;
}
const std::vector<FunctionToUpdate> Error::table
{ // <-- here the Error happens
{ 100, &testFunctionA, { {177}}},
{ 1948, &testFunctionB, { {314}}},
};
int main()
{
Error error;
}
Your code has a few issues
First, the correct initialization of static member Error::table would be as follows:
const std::vector<FunctionToUpdate> Error::table
{
{ 100, &Error::testFunctionA, { { {177} }, { {"string"} } }},
{ 1948, &Error::testFunctionB, { { {314} }, { {"string"} } } }
};
Note that the syntax &Error::testFunctionA for addressing the member function pointer. Additionally, the Params has two vectors. One is std::vector<int> and the other is std::vector<std::string>. In your code, the std::vector<std::string> has not been mentioned.
In FunctionToUpdate the member function pointer type is wrong. Using typed member function pointer, you could
// forward declaration
class Error;
// member function pointer type
using ErrorFunType = void(Error::*)(int, Params);
struct FunctionToUpdate
{
int Version;
ErrorFunType Function;
Params Parameters;
};
Secondly, the call to pointer to the member function in Error::Error() is wrong. It needs an (Error class) instance to call with. For example:
for (auto functionToUpdate : table)
{
(this->*functionToUpdate.Function)(
functionToUpdate.Version, functionToUpdate.Parameters
);
// or more generic `std::invoke` (since c++17)
// std::invoke(functionToUpdate.Function
// , this, functionToUpdate.Version
// , functionToUpdate.Parameters);
// ...
}
The above changes will make, your code compiles again!
In case of wondering, how to handle the pointer to member function with std::function, (one way) to wrap the instance to call the member along with the std::function type.
Following is the example:
// forward declaration
class Error;
// member function pointer
using ErrorFunType = std::function<void(Error*, int, Params)>;
struct FunctionToUpdate
{
int Version;
ErrorFunType Function;
Params Parameters;
};
now in Error::Error()
Error::Error()
{
for (auto functionToUpdate : table)
{
functionToUpdate.Function(this
, functionToUpdate.Version, functionToUpdate.Parameters);
}
}
See a demo
I currently wish to have a vector of objects where each object has differing properties.
Intended outcome:
//v is a vector
v.push_back(ttSaveObj(5, "int example"));
v.push_back(ttSaveObj("Hello, world!", "string example"));
std::cout << v[0].data << " " << v[0].variableName << std::endl; //Intended Output: 5 int example
std::cout << v[1].data << " " << v[1].variableName << std::endl; //Intended Output: Hello, world! string example
Based on this answer I tried having a constructor function for the class with <void*> in the template, but this seems just create a pointer to void (as I partially expected).
ttSaveObj.hpp:
template <typename T>
class ttSaveObj {
public:
ttSaveObj(T pVar, std::string pName) {
data = pVar;
variableName = pName;
};
~ttSaveObj() {};
std::string variableName;
T data;
};
ttGameObj.hpp:
#include "ttSaveObj.hpp"
class ttGameObj {
public:
ttGameObj();
~ttGameObj();
std::vector<ttSaveObj<void*>> data;
};
ttGameObj.cpp:
#include "ttGameObj.hpp"
ttGameObj::ttGameObj() {
int asdf = 5;
int * test = &asdf;
data.push_back(ttSaveObj<void*>(test, "X"));
std::cout << &data[0].data << " " << data[0].variableName << std::endl; //Output: 0x15fb770 X
}
Anything that will help me get closer to my intended outcome is appreciated, thanks!
The objects you put in the vector seem to have two data members: variableName, which is of fixed std::string type, and a data field, which is of varying type.
You may consider using C++17's std::variant (or Boost's variant implementation) for the data field. For example, if you plan to support the types int, float and std::string for your data, you can use a std::variant<int, float, std::string>.
There's also std::any, if you want to store instances of any type (that satisfy the requirements described in the std::any documentation).
In modern C++ I'd suggest to avoid the C-style void*, and use it only if strictly necessary (e.g. if you are at some legacy C API boundary): there are safer, more robust and higher-level alternatives to it.
Another option (if it makes better sense for your design) is to define a base class (interface) for the objects you want to put in your vector, and define custom classes that implement this interface. In this case, I suggest using smart pointers (like e.g. std::unique_ptr or std::shared_ptr) to manage those objects in a simple and safe way (I saw another answer here that used raw pointers, requiring explicit new/delete - actually in that code there were news but no delete, with consequent resource leaks).
E.g.:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace std;
// Interface for an element to be inserted in the vector
class IElement
{
public:
IElement() {}
virtual ~IElement() {}
virtual string ToString() = 0;
// Other virtual methods ...
};
class IntElement : public IElement
{
public:
explicit IntElement(int n) : _n{ n } {}
virtual string ToString() override
{
return to_string(_n);
}
private:
int _n;
};
class StringElement : public IElement
{
public:
explicit StringElement(const string& s) : _s{ s } {}
virtual string ToString() override
{
return _s;
}
private:
string _s;
};
int main()
{
vector<shared_ptr<IElement>> elements;
elements.push_back(make_shared<IntElement>(10));
elements.push_back(make_shared<IntElement>(20));
elements.push_back(make_shared<StringElement>("Hello"));
elements.push_back(make_shared<StringElement>("World"));
for (const auto& e : elements)
{
cout << e->ToString() << '\n';
}
}
Output:
10
20
Hello
World
If you are using C++11 then you can use the tuple class in the standard library. You could make this object like so:
auto v = std::make_tuple(ttSaveObj(5, "int example"), ttSaveObj("Hello, world!", "string example"))
std::cout << std::get<0>(v).data << " " << std::get<0>(v).variableName << std::endl;
There is a drawback though that the index for access is a template argument and must therefore be known at compile time, meaning that you can't loop through the elements. Also the types of the elements in the tuple must be known at compile time.
If I understood your goals correctly, Java-like approach could take place, but you should wrap the vector to never forget the clean up.
// Example program
#include <iostream>
#include <string>
#include <vector>
#include <string.h>
#include <memory>
using std::vector;
class Object
{
public:
explicit Object() {}
virtual ~Object() {}
virtual const char* toString() const = 0;
};
class StringObject : public Object
{
public:
explicit StringObject(const char* string) : Object()
{
if(string != 0)
{
m_value = new char[strlen(string) + 1];
strcpy(((char*)m_value), string);
} else
{
m_value = new char[1];
m_value[0] = 0;
}
}
virtual ~StringObject()
{
delete m_value;
}
virtual const char* toString() const
{
return (const char*)m_value;
}
private:
char* m_value;
};
class IntObject : public Object
{
public:
explicit IntObject(int val) : Object()
{
m_value = val;
}
virtual ~IntObject()
{
}
virtual const char* toString() const
{
return std::to_string(m_value).c_str();
}
private:
int m_value;
};
int main()
{
auto vec = vector<std::unique_ptr<Object>>();
vec.push_back(std::make_unique<IntObject>(9));
vec.push_back(std::make_unique<IntObject>(11));
vec.push_back(std::make_unique<StringObject>("hello"));
vec.push_back(std::make_unique<StringObject>("world"));
for(const auto& v : vec)
{
std::cout << v.get()->toString() << " ";
}
}
Output, as expected, "9 11 hello world".
thanks in advance for your support.
I'm using C++11 and I want to store public member functions of some classes for later use as callback functions; e.g. I want to store some functions that matches this template: void(classname::*)(void). As far as I know, I have to store their objects too, It's fine. For example:
// PSEUDO CODE
class A {
public:
void myfunc() {}
}myobj;
class B {
public:
void myfunc2() {}
}myobj2;
/* storing */
mystorageclass storage;
storage.push(&myobj, &A::myfunc);
storage.push(&myobj2, &B::myfunc2);
/* call them back */
(storage[0].object->*(storage[0].callback))();
(storage[1].object->*(storage[1].callback))();
Is there any safe and generic way to do that? Actually I've found a way, but I'm not sure how much it's portable across processors or compilers.
//test.cpp - compiled with: g++ test.cpp -o test -std=c++11
#include <iostream>
#include <vector>
class A {
public:
void myfunc() { std::cout << "Test A::myfunc()" << std::endl; }
}myobj;
class B {
public:
void myfunc2() { std::cout << "Test B::myfunc2()" << std::endl; }
}myobj2;
struct Callback {
void* object;
void(* method)(void*);
};
std::vector<Callback> callbackList;
template<typename FunctionPtr>
void add(void* object, FunctionPtr fptr) {
Callback cb;
cb.object = object;
cb.method = (void(*)(void*))(*(void**)(&fptr));
callbackList.push_back(cb);
}
int main() {
//add to list for later use
add(&myobj, &A::myfunc);
add(&myobj2, &B::myfunc2);
//call them back
callbackList[0].method(callbackList[0].object);
callbackList[1].method(callbackList[1].object);
}
And another way to do; I feel this is much more safe:
//test2.cpp - compiled with: g++ test2.cpp -o test2 -std=c++11
#include <iostream>
#include <vector>
class A {
public:
void myfunc() { std::cout << "Test A::myfunc()" << std::endl; }
}myobj;
class B {
public:
void myfunc2() { std::cout << "Test B::myfunc2()" << std::endl; }
}myobj2;
struct Callback {
struct A;
A* object;
void(A::* method)();
void call() {
(object->*method)();
}
};
std::vector<Callback> callbackList;
template<typename FunctionPtr>
void add(void* object, FunctionPtr fptr) {
Callback cb;
cb.object = (Callback::A*)object;
cb.method = (void(Callback::A::*)())(fptr);
callbackList.push_back(cb);
}
int main() {
//add to list for later use
add(&myobj, &A::myfunc);
add(&myobj2, &B::myfunc2);
//call them back
callbackList[0].call();
callbackList[1].call();
}
Does these usages are safe? Or what do you suggest instead of these.
Thanks.
Replace Callback with std::function<void()>.
Replace add with
template<class T, class R, class U>
void add(T* object, R(U::*ptr)()) {
Callback cb = [object, ptr]{ object->ptr(); };
callbackList.push_back(cb);
// or just
// callbackList.push_back([object, ptr]{ object->ptr(); });
}
note that this supports passing in pointers-to-parent member functions, and callbacks that do not return void and discarding the result.
std::function stores a generic "call this later". You pass a type compatible with the return value, and args compatible with what you want to call later, in the template signature argument of std::function<signature>. In this case, <void()>.
Problem with the second version
In the line
cb.method = (void(*)(void*))(*(void**)(&fptr));
you are casting a function pointer to void**. I am not sure that is supported by the standard. My guess is it is not. I know casting a function pointer to void* is not supported by the standard. See Print an address of function in C++, g++/clang++ vs vc++ , who is rght? for details.
And then, you proceed to use:
callbackList[1].method(callbackList[1].object);
This relies on conventions used by a compiler to pass this as the first hidden argument when calling a member function of a class. There is no guarantee that the method is used by all compilers. The standard does not explicitly state that.
Problem with the third/last version
You are using:
cb.object = (Callback::A*)object;
cb.method = (void(Callback::A::*)())(fptr);
regardless of whether the object type is A or B. This is cause for undefined behavior. The standard does not support casting of an object pointer to any old pointer type.
A Cleaner Version
Use a base class for Callback.
struct Callback {
virtual ~Callback() = 0;
virtual void call() = 0;
};
Then, use a class template for the real Callbacks.
template <typename T>
struct RealCallback : public Callback
{
RealCallback(T* obj, void (T::*m)(void)) : object(obj), method(m) {}
virtual void call()
{
(object->*method)();
}
T* object;
void (T::*method)();
};
With this, you won't be able to store a list of Callback objects but you can store a list of shared_ptr<Callback>s.
std::vector<std::shared_ptr<Callback>> callbackList;
Here's a complete program that does not rely on any ugly casts and works perfectly.
//test.cpp - compiled with: g++ test.cpp -o test -std=c++11
#include <iostream>
#include <vector>
#include <memory>
class A {
public:
void myfunc() { std::cout << "Test A::myfunc() on " << this << std::endl; }
}myobj;
class B {
public:
void myfunc2() { std::cout << "Test B::myfunc2() on " << this << std::endl; }
}myobj2;
struct Callback {
virtual void call() = 0;
};
template <typename T>
struct RealCallback : public Callback
{
RealCallback(T* obj, void (T::*m)(void)) : object(obj), method(m) {}
virtual void call()
{
(object->*method)();
}
T* object;
void (T::*method)();
};
std::vector<std::shared_ptr<Callback>> callbackList;
template<typename T>
void add(T* object, void (T::*fptr)()) {
RealCallback<T>* cb = new RealCallback<T>(object, fptr);
callbackList.push_back(std::shared_ptr<Callback>(cb));
}
int main() {
//add to list for later use
add(&myobj, &A::myfunc);
add(&myobj2, &B::myfunc2);
std::cout << "myobj: " << &myobj << std::endl;
std::cout << "myobj2: " << &myobj2 << std::endl;
//call them back
callbackList[0]->call();
callbackList[1]->call();
}
Update, in response to comment by Yakk
I think Yakk's suggestion makes sense. You can remove the classes Callback and RealCallback with
using Callback = std::function<void()>;
std::vector<Callback> callbackList;
Then, add can be simplified to:
template<class T>
void add(T* object, void(T::*ptr)()) {
callbackList.push_back([object, ptr]{ (object->*ptr)();});
}
With those changes, main needs to be slightly updated to:
int main() {
//add to list for later use
add(&myobj, &A::myfunc);
add(&myobj2, &B::myfunc2);
std::cout << "myobj: " << &myobj << std::endl;
std::cout << "myobj2: " << &myobj2 << std::endl;
// Updated. Can't use callbackList[0]->call();
//call them back
callbackList[0]();
callbackList[1]();
}
Try with std::function or std::bindboth of them need to keep the reference to the instance:
#include <string>
#include <iostream>
#include <functional>
using namespace std;
class MyClass
{
int _value;
public:
MyClass(int value)
{
_value = value;
}
void food()
{
cout << "Foo is doing something whit value: " << _value << endl;
}
void bar()
{
cout << "Bar is doing something whit value: " << _value << endl;
}
};
int main()
{
MyClass* c1 = new MyClass(1);
MyClass* c2 = new MyClass(2);
cout << "Using 'std::function':" << endl;
std::function<void(MyClass&)> food = &MyClass::food;
std::function<void(MyClass&)> bar = &MyClass::bar;
food(*c1);
bar(*c1);
food(*c2);
bar(*c2);
cout << "Using 'std::bind':" << endl;
auto foodBind = std::bind(&MyClass::food, std::placeholders::_1);
auto barBind = std::bind(&MyClass::bar, std::placeholders::_1);
foodBind(*c1);
barBind(*c1);
foodBind(*c2);
barBind(*c2);
system("PAUSE");
};
the Output is:
Consider the following setup.
Base class:
class Thing {
int f1;
int f2;
Thing(NO_INIT) {}
Thing(int n1 = 0, int n2 = 0): f1(n1),f2(n2) {}
virtual ~Thing() {}
virtual void doAction1() {}
virtual const char* type_name() { return "Thing"; }
}
And derived classes that are different only by implementation of methods above:
class Summator {
Summator(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 += f2; }
virtual const char* type_name() override { return "Summator"; }
}
class Substractor {
Substractor(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 -= f2; }
virtual const char* type_name() override { return "Substractor"; }
}
The task I have requires ability to change class (VTBL in this case) of existing objects on the fly. This is known as dynamic subclassing if I am not mistaken.
So I came up with the following function:
// marker used in inplace CTORs
struct NO_INIT {};
template <typename TO_T>
inline TO_T* turn_thing_to(Thing* p)
{
return ::new(p) TO_T(NO_INIT());
}
that does just that - it uses inplace new to construct one object in place of another. Effectively this just changes vtbl pointer in objects. So this code works as expected:
Thing* thing = new Thing();
cout << thing->type_name() << endl; // "Thing"
turn_thing_to<Summator>(thing);
cout << thing->type_name() << endl; // "Summator"
turn_thing_to<Substractor>(thing);
cout << thing->type_name() << endl; // "Substractor"
The only major problems I have with this approach is that
a) each derived classes shall have special constructors like Thing(NO_INIT) {} that shall do precisely nothing. And b) if I will want to add members like std::string to the Thing they will not work - only types that have NO_INIT constructors by themselves are allowed as members of the Thing.
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ? I have a feeling that std::move semantic may help to solve 'b' somehow but not sure.
Here is the ideone of the code.
(Already answered at RSDN http://rsdn.ru/forum/cpp/5437990.1)
There is a tricky way:
struct Base
{
int x, y, z;
Base(int i) : x(i), y(i+i), z(i*i) {}
virtual void whoami() { printf("%p base %d %d %d\n", this, x, y, z); }
};
struct Derived : Base
{
Derived(Base&& b) : Base(b) {}
virtual void whoami() { printf("%p derived %d %d %d\n", this, x, y, z); }
};
int main()
{
Base b(3);
Base* p = &b;
b.whoami();
p->whoami();
assert(sizeof(Base)==sizeof(Derived));
Base t(std::move(b));
Derived* d = new(&b)Derived(std::move(t));
printf("-----\n");
b.whoami(); // the compiler still believes it is Base, and calls Base::whoami
p->whoami(); // here it calls virtual function, that is, Derived::whoami
d->whoami();
};
Of course, it's UB.
For your code, I'm not 100% sure it's valid according to the standard.
I think the usage of the placement new which doesn't initialize any member variables, so to preserve previous class state, is undefined behavior in C++. Imagine there is a debug placement new which will initialize all uninitialized member variable into 0xCC.
union is a better solution in this case. However, it does seem that you are implementing the strategy pattern. If so, please use the strategy pattern, which will make code a lot easier to understand & maintain.
Note: the virtual should be removed when using union.
Adding it is ill-formed as mentioned by Mehrdad, because introducing virtual function doesn't meet standard layout.
example
#include <iostream>
#include <string>
using namespace std;
class Thing {
int a;
public:
Thing(int v = 0): a (v) {}
const char * type_name(){ return "Thing"; }
int value() { return a; }
};
class OtherThing : public Thing {
public:
OtherThing(int v): Thing(v) {}
const char * type_name() { return "Other Thing"; }
};
union Something {
Something(int v) : t(v) {}
Thing t;
OtherThing ot;
};
int main() {
Something sth{42};
std::cout << sth.t.type_name() << "\n";
std::cout << sth.t.value() << "\n";
std::cout << sth.ot.type_name() << "\n";
std::cout << sth.ot.value() << "\n";
return 0;
}
As mentioned in the standard:
In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [ Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if an object of this standard-layout union type contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of standard-layout struct members; see 9.2. — end note ]
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ?
If you have fixed set of sub-classes then you may consider using algebraic data type like boost::variant. Store shared data separately and place all varying parts into variant.
Properties of this approach:
naturally works with fixed set of "sub-classes". (though, some kind of type-erased class can be placed into variant and set would become open)
dispatch is done via switch on small integral tag. Sizeof tag can be minimized to one char. If your "sub-classes" are empty - then there will be small additional overhead (depends on alignment), because boost::variant does not perform empty-base-optimization.
"Sub-classes" can have arbitrary internal data. Such data from different "sub-classes" will be placed in one aligned_storage.
You can make bunch of operations with "sub-class" using only one dispatch per batch, while in general case with virtual or indirect calls dispatch will be per-call. Also, calling method from inside "sub-class" will not have indirection, while with virtual calls you should play with final keyword to try to achieve this.
self to base shared data should be passed explicitly.
Ok, here is proof-of-concept:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
Output is:
Summator 12 7
Substractor 5 7
size: 2
LIVE DEMO on Coliru
Full Code (it uses some C++14 features, but can be mechanically converted into C++11):
#define BOOST_VARIANT_MINIMIZE_SIZE
#include <boost/variant.hpp>
#include <type_traits>
#include <functional>
#include <iostream>
#include <utility>
using namespace std;
/****************************************************************/
// Boost.Variant requires result_type:
template<typename T, typename F>
struct ResultType
{
mutable F f;
using result_type = T;
template<typename ...Args> T operator()(Args&& ...args) const
{
return f(forward<Args>(args)...);
}
};
template<typename T, typename F>
auto make_result_type(F &&f)
{
return ResultType<T, typename decay<F>::type>{forward<F>(f)};
}
/****************************************************************/
// Proof-of-Concept
template<typename Base, typename ...Ts>
struct SubVariant
{
Base shared_data;
boost::variant<Ts...> sub;
template<typename Visitor>
friend auto apply(Visitor visitor, SubVariant &operand)
{
using result_type = typename common_type
<
decltype( visitor(shared_data, declval<Ts&>()) )...
>::type;
return boost::apply_visitor(make_result_type<result_type>([&](auto &x)
{
return visitor(operand.shared_data, x);
}), operand.sub);
}
};
/****************************************************************/
// Demo:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
use return new(p) static_cast<TO_T&&>(*p);
Here is a good resource regarding move semantics: What are move semantics?
You simply can't legally "change" the class of an object in C++.
However if you mention why you need this, we might be able to suggest alternatives. I can think of these:
Do v-tables "manually". In other words, each object of a given class should have a pointer to a table of function pointers that describes the behavior of the class. To modify the behavior of this class of objects, you modify the function pointers. Pretty painful, but that's the whole point of v-tables: to abstract this away from you.
Use discriminated unions (variant, etc.) to nest objects of potentially different types inside the same kind of object. I'm not sure if this is the right approach for you though.
Do something implementation-specific. You can probably find the v-table formats online for whatever implementation you're using, but you're stepping into the realm of undefined behavior here so you're playing with fire. And it most likely won't work on another compiler.
You should be able to reuse data by separating it from your Thing class. Something like this:
template <class TData, class TBehaviourBase>
class StateStorageable {
struct StateStorage {
typedef typename std::aligned_storage<sizeof(TData), alignof(TData)>::type DataStorage;
DataStorage data_storage;
typedef typename std::aligned_storage<sizeof(TBehaviourBase), alignof(TBehaviourBase)>::type BehaviourStorage;
BehaviourStorage behaviour_storage;
static constexpr TData *data(TBehaviourBase * behaviour) {
return reinterpret_cast<TData *>(
reinterpret_cast<char *>(behaviour) -
(offsetof(StateStorage, behaviour_storage) -
offsetof(StateStorage, data_storage)));
}
};
public:
template <class ...Args>
static TBehaviourBase * create(Args&&... args) {
auto storage = ::new StateStorage;
::new(&storage->data_storage) TData(std::forward<Args>(args)...);
return ::new(&storage->behaviour_storage) TBehaviourBase;
}
static void destroy(TBehaviourBase * behaviour) {
auto storage = reinterpret_cast<StateStorage *>(
reinterpret_cast<char *>(behaviour) -
offsetof(StateStorage, behaviour_storage));
::delete storage;
}
protected:
StateStorageable() = default;
inline TData *data() {
return StateStorage::data(static_cast<TBehaviourBase *>(this));
}
};
struct Data {
int a;
};
class Thing : public StateStorageable<Data, Thing> {
public:
virtual const char * type_name(){ return "Thing"; }
virtual int value() { return data()->a; }
};
Data is guaranteed to be leaved intact when you change Thing to other type and offsets should be calculated at compile-time so performance shouldn't be affected.
With a propert set of static_assert's you should be able to ensure that all offsets are correct and there is enough storage for holding your types. Now you only need to change the way you create and destroy your Things.
int main() {
Thing * thing = Thing::create(Data{42});
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
turn_thing_to<OtherThing>(thing);
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
Thing::destroy(thing);
return 0;
}
There is still UB because of not reassigning thing which can be fixed by using result of turn_thing_to
int main() {
...
thing = turn_thing_to<OtherThing>(thing);
...
}
Here is one more solution
While it slightly less optimal (uses intermediate storage and CPU cycles to invoke moving ctors) it does not change semantic of original task.
#include <iostream>
#include <string>
#include <memory>
using namespace std;
struct A
{
int x;
std::string y;
A(int x, std::string y) : x(x), y(y) {}
A(A&& a) : x(std::move(a.x)), y(std::move(a.y)) {}
virtual const char* who() const { return "A"; }
void show() const { std::cout << (void const*)this << " " << who() << " " << x << " [" << y << "]" << std::endl; }
};
struct B : A
{
virtual const char* who() const { return "B"; }
B(A&& a) : A(std::move(a)) {}
};
template<class TO_T>
inline TO_T* turn_A_to(A* a) {
A temp(std::move(*a));
a->~A();
return new(a) B(std::move(temp));
}
int main()
{
A* pa = new A(123, "text");
pa->show(); // 0xbfbefa58 A 123 [text]
turn_A_to<B>(pa);
pa->show(); // 0xbfbefa58 B 123 [text]
}
and its ideone.
The solution is derived from idea expressed by Nickolay Merkin below.
But he suspect UB somewhere in turn_A_to<>().
I have the same problem, and while I'm not using it, one solution I thought of is to have a single class and make the methods switches based on a "item type" number in the class. Changing type is as easy as changing the type number.
class OneClass {
int iType;
const char* Wears() {
switch ( iType ) {
case ClarkKent:
return "glasses";
case Superman:
return "cape";
}
}
}
:
:
OneClass person;
person.iType = ClarkKent;
printf( "now wearing %s\n", person.Wears() );
person.iType = Superman;
printf( "now wearing %s\n", person.Wears() );
I've been trying to figure out how to properly pair a function with an id. What I've been doing so far is a C-way of doing it:
#include <iostream>
void PrintA();
void PrintB();
struct Function
{
int id;
void (*function)();
};
static const Function functions[] =
{
{1, PrintA},
{2, PrintB},
{0, 0}
};
void PrintA()
{
std::cout << "A" << std::endl;
};
void PrintB()
{
std::cout << "B" << std::endl;
};
int main()
{
int id = 1;
for(int i = 0; functions[i].function != 0 ; i++)
{
if(functions[i].id == id)
{
functions[i].function();
}
}
}
I'm trying to achieve the same functionality using functors in C++. I suppose I need to use inheritance to be able to store the different functions in the same array meaning I also need to use pointers for the array in order to prevent slicing. Is the following way of doing this the correct way and are there any alternatives?
Also is there any simpler version to call the operator than how I did it?
#include <iostream>
#include <memory>
class Base
{
public:
virtual void operator()() = 0;
};
class PrintA : public Base
{
public:
void operator()();
};
void PrintA::operator()()
{
std::cout << "A" << std::endl;
}
class PrintB : public Base
{
public:
void operator()();
};
void PrintB::operator()()
{
std::cout << "B" << std::endl;
}
struct Functor
{
int id;
std::shared_ptr<Base> function;
};
static Functor functors[] =
{
{1, std::shared_ptr<Base>(new PrintA)},
{2, std::shared_ptr<Base>(new PrintB)},
{0, 0}
};
int main()
{
int id = 2;
for(int i = 0; functors[i].function != 0 ; i++)
{
if(functors[i].id == id)
{
functors[i].function->operator()();
}
}
}
EDIT: I have to use a rather old GCC version making it impossible to use c++11 features. Boost is available, though. I suppose an std::map would be a good idea, but what I was really asking (didn't really make it clear) was that is there a better way to store the functions than shared_ptr. I suppose that std::function/boost::function way is the way to do it.
In C++11 (or Boost, if you're stuck in the past), this kind of type erasure is available in the function wrapper; and there's always been map to perform the ID-based lookup. So your example is as simple as:
#include <map>
#include <functional>
#include <iostream>
// Note: This will be a lot messier if you're stuck with a pre-2011 compiler.
// You'll need to define the functors (or functions) separately, and either
// initialise the map with the result of a function call (possibly using
// Boost.Assign), or write some code somewhere else to populate it.
//
// Or use an array, with lookup code like your C implementation.
std::map<int, std::function<void()>> functors {
{1, [](){std::cout << "A" << std::endl;}},
{2, [](){std::cout << "B" << std::endl;}}
};
int main() {
functors[2]();
}
As noted in the comments, if the real situation is as simple as the example, you could use a function pointer rather than function (and still initialise it with a lambda, if you like), and an array (indexed by id) rather than a map. My example assumes that you want a more general solution, mapping arbitrary values to arbitrary functors.
Simple:
#include <functional>
#include <iostream>
#include <vector>
void sayA() { std::cout << "A" << std::endl; }
void sayB() { std::cout << "B" << std::endl; }
struct Foo
{
explicit Foo(int i) : i_(i) {}
void operator()() const { std::cout << "foo " << i_<< "!" << std::endl; }
int i_;
};
std::vector<std::function<void()>> funcs{ sayA, sayB, Foo(42) };
int main()
{
for (const auto& f : funcs) f();
}