This question already has answers here:
Inheritance in std::map with base class as value
(4 answers)
Closed last month.
I would like to have a function that accepts a std::map containing a (pointer to a) base class, but I can't get it to work. Here is my minimal and simplified example:
struct Entity {
int i;
Entity(const int i_) : i(i_) {}
virtual ~Entity() {}
};
struct A : public Entity {
bool a;
A(const int i_, const bool a_) : Entity(i_), a(a_) {}
};
void efunc(const std::map<int, std::shared_ptr<Entity>>& m) {
for (auto& it : m) {
std::cout << it.second->i << std::endl;
}
}
int main() {
std::map<int, std::shared_ptr<A>> aMap;
std::shared_ptr<A> myA = std::make_shared<A>(1, true);
aMap.insert({myA->i, myA});
// efunc(aMap); // DOES NOT WORK
}
Obviously simply passing the map this way is not allowed, but how can I make it work?
As a bonus, how would I detect the type in the map so that I can execute code specific to that subclass?
Thank you in advance!
Update: Using templates seems to do the trick, this is what I'm using right now:
template <class T>
void tfunc(const std::map<int, std::shared_ptr<T>>& m) {
for (auto& it : m) {
std::cout << it.second->i << std::endl;
}
}
It does feel a bit strange, since I loose IntelliSense and I don't understand why the compiler is not giving me an error. I feel like concepts might help (e.g. to make sure T inherits Entity), but this is beyond what I need right now.
Thank you again for all the responses!
Update 2: Alright, here it is using concepts to ensure that the template containst the member i:
template <class T>
concept hasI = requires(T a) { a.i; };
template <class T>
concept inheritsEntity = std::derived_from<T, Entity>;
template <hasI T>
/// alternative: template<inheritsEntity T>
void tfunc(const std::map<int, std::shared_ptr<T>>& m) {
for (auto& it : m) {
std::cout << it.second->i << std::endl;
}
}
To answer your first question, you could use template programming; the compiler will generate the code specific to the required type for you:
template <class EntityType>
void efunc_template(const std::map<int, std::shared_ptr<EntityType>>& m) {
for (auto& it : m) {
std::cout << it.second->i << std::endl;
}
}
The function can then be called in your main function using:
efunc_template<A>(aMap);
Regarding your second question (how to execute code specific to your type), check can be done at compile time using:
template <class EntityType>
void efunc_template(const std::map<int, std::shared_ptr<EntityType>>& m) {
for (auto& it : m) {
if constexpr (std::is_same_v<A, EntityType>) {
std::cout << "Type is A" << std::endl;
} else {
std::cout << "Other type: " << typeid(EntityType).name() << std::endl;
}
std::cout << it.second->i << std::endl;
}
}
You can make aMap a std::map<int, std::shared_ptr<Entity>> and still hold shared pointers to instances of A.
In the code below myA which will be stored in the map is of type std::shared_ptr<Entity> but is initialized with a shared pointer to an instance of class A. This is OK because A is derived from Entity.
//----------------------------VVVVVV--------
std::map<int, std::shared_ptr<Entity>> aMap;
//--------------VVVVVV-------------------------V-----------
std::shared_ptr<Entity> myA = std::make_shared<A>(1, true);
aMap.insert({ myA->i, myA });
efunc(aMap); // Works now.
As commented below, myA can also be std::shared_ptr<A> and still be stored in aMap:
std::shared_ptr<A> myA = std::make_shared<A>(1, true);
Alternatively, if using efunc is quite rare, you can keep aMap as std::map<int, std::shared_ptr<A>>.
Then whenever you need to call efunc, create a temporary std::map<int, std::shared_ptr<Entity>> containing a copy of the content of aMap and use it to call efunc.
The shared pointers will still refer to your original objects.
It's inefficient, but if you don't use efunc frequently it might be sufficient.
Change the declaration of your std::map variable from :
std::map<int, std::shared_ptr<A>> aMap;
to :
std::map<int, std::shared_ptr<Entity>> aMap;
This way, the map matches what's expected by your efunc function.
Using inheritance as you did, you can indeed insert in your aMap data structure instances of type Entity as well as instances whose the type derivates from Entity. This is the case for struct A.
To detect the type in the map, you can either use a scoped enum as member within the Entity struct, or using the typeid operator, which returns an instance of std::type_info, with which you can get the name of the type.
However, the returned name is not guaranteed to be the same across implementations.
======== output from Clang ========
myint has type: i
mystr has type: NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
======== output from MSVC ========
myint has type: int
mystr has type: class std::basic_string<char,struct > std::char_traits,class std::allocator >
For this reason, you might want to use dynamic_cast instead, such as :
class Base {
public:
virtual ~Base() {}
};
class T1Base : public Base {};
class T2Base : public Base {};
template <typename T> class T1 : public T1Base {};
template <typename T> class T2 : public T2Base {};
int main()
{
Base *b = find_by_name();
if (dynamic_cast<T1Base*>(b))
cout << "T1" << endl;
else if (dynamic_cast<T2Base*>(b))
cout << "T2" << endl;
else
cout << "unknown" << endl;
delete b;
return 0;
}
Related
I am trying to use auto in combination with a virtual function. Please consider the following code:
#include <iostream>
#include <vector>
struct foo {
virtual auto get() = 0;
};
template <typename T>
struct bar : foo
{
virtual T get() override {return new T;};
};
int main() {
std::vector<foo*> Vec;
Vec.push_back(new bar<decltype(1333)>);
Vec.push_back(new bar<decltype(3.14159)>);
Vec.push_back(new bar<decltype(true)>);
std::cout << Vec[0]->get() << std::endl;
std::cout << Vec[1]->get() << std::endl;
std::cout << Vec[2]->get() << std::endl;
}
You can see online at Godbolt that code does not compile. The compiler returns:
error: virtual function cannot have deduced return type
Please help me to fix the above code.
This will not work in C++. Vec[i]->get() must imply a return type at compile time. How to do something like this depends on your needs. Assuming you have a closed set of types you want to work with, you can use std::variant:
#include <iostream>
#include <variant>
#include <vector>
struct foo {
using ReturnType = std::variant<int, bool, double>;
virtual ReturnType get() = 0;
// you need a virtual destructor in all base classes
virtual ~foo() = default;
};
template <typename T>
struct bar : public foo {
using foo::ReturnType;
ReturnType get() override {
return T{};
};
};
int main() {
std::vector<foo*> Vec;
Vec.push_back(new bar<decltype(1333)>);
Vec.push_back(new bar<decltype(3.14159)>);
Vec.push_back(new bar<decltype(true)>);
auto const visiter = [](auto const elm) { std::cout << elm << '\n'; };
for (auto& elm : Vec) {
std::visit(visiter, elm->get());
delete elm; // don't leak memory
elm = nullptr;
}
}
Don't use raw-owning pointers in this context. They will lead to memory leaks.
First, see here: C++ virtual function return type
Your problem is here:
virtual auto get() = 0;
A virtual function needs to have a known return type, or how will the overrides be checked to ensure covariance of their return types?
In particular, you seem to want get() overrides which return int, double, and bool. But these types are not covariant with anything (they have no base class), so you can't do that, because there is no type you can put in place of auto that will actually work.
You could make a base class for the value types and then store wrappers derived from that:
struct BaseValue {};
struct IntValue : BaseValue {};
// etc
But then it's hard to see how you can do anything useful with the BaseValue* you'd get().
This question already has an answer here:
Force explicit template instantiation with CRTP
(1 answer)
Closed 8 years ago.
So I read this article about using static initialization to register classes (http://quantumgraphics.blogspot.nl/2014/11/abusing-static-initialization.html). It's exactly what I need so I decided to implement it. I couldn't get it to work however, so I made a little test case to make sure I got the details right. Turns out even a simple example doesn't work (http://ideone.com/HDr8ZM):
#include <iostream>
int a = 0;
template<
class T
>
class Scriptable {
protected:
struct Proxy
{
Proxy() {
std::cout << "Proxy was executed! ID: " << T::id << std::endl;
a++;
}
};
static Proxy proxy_;
} ;
template<
class T
>
typename Scriptable<T>::Proxy Scriptable<T>::proxy_;
class Object : public Scriptable<Object> {
public:
constexpr static auto id = "[Object]";
} ;
int main() {
std::cout << "Done " << a << std::endl;
}
So basically what needs to happen (or more precisely, what I want to happen) is that the Proxy constructor should be executed before main. I want to use the the Proxy constructor to register the class with some singleton base class factory, but I don't think that's related to this code not working.
Can someone point me in the right direction? I'm probably missing a compiler flag or something (the example should compile with just the -std=c++11 flag). Or is there maybe a better way to do what I'm trying here?
Any help is greatly appreciated!
With Pradhan's link I was able to cook up what I needed:
#include <iostream>
int a = 0;
template <typename T, T /*unnamed*/>
struct nnb_ForceInit { };
template<
class T
>
class Scriptable {
public:
struct nnb_Proxy {
nnb_Proxy() {
std::cout << "Proxy was executed! ID: " << T::id << std::endl;
a++;
}
};
static nnb_Proxy __nnb_proxy__;
typedef nnb_ForceInit<nnb_Proxy&, __nnb_proxy__> __nnb_typedef_dummy__;
} ;
template<
class T
>
typename Scriptable<T>::nnb_Proxy Scriptable<T>::__nnb_proxy__;
class Object : public Scriptable<Object> {
public:
constexpr static auto id = "[Object]";
};
class Image : public Scriptable<Image> {
public:
constexpr static auto id = "[Image]";
};
class Error : public Scriptable<Error> {
public:
constexpr static auto id = "[Error]";
} ;
int main() {
std::cout << "Done " << a << std::endl;
}
I don't have a very clear idea how it works exactly but it seems to do what I want/works fine, so I guess that's it.
It doesn't work because there's no reason for your Proxy to ever get constructed. In this case, your main() doesn't even construct an Object - so why would the Proxy get constructed? You'd have to at least do that:
int main() {
Object o;
std::cout << "Done " << a << std::endl;
}
But then, simply constructing o doesn't reference the proxy in any way, so there's still no reason for it to be constructed. You'll have to touch it somehow. Simplest is to just reference it in Scriptable's constructor:
Scriptable() {
proxy_; // this line throws a warning, since this line does nothing,
// so replace it with something reasonable. but this line is
// enough to force proxy_ to be instantiated.
}
If I add those two bits (Object o; and the Scriptable constructor), then your code yields:
Proxy was executed! ID: [Object]
Done 1
Another way is to actually declare the proxy_ within the constructor:
Scriptable() {
static Proxy proxy_;
}
I have a kind of object registry where objects can be registered. This should be done in the initialization phase. E.g.
class ObjectBase {
protected:
bool active;
public:
void activate() { active = true; }
};
template<typename T>
class Object : public ObjectBase {
T value;
};
class Registry {
public:
template<typename T>
static std::shared_ptr<Object<T>> registerObject() {
return std::make_shared<Object<T>>();
}
namespace {
std::shared_ptr< Object<int> > myObject = Registry::registerObject<int>();
}
Now I want the active value set at initialisation (and constructor parameters are not an option, as this is but one of many). What would be neat is if I were able to do the following:
namespace {
std::shared_ptr< Object<int> > myObject = Registry::registerObject<int>()->activate();
}
However I don't see a way for activate() to return a pointer of type Object (unless I make it a template as well and do a dynamic cast, however this seems ugly), lest so a shared pointer. Or is there some way? Alternatively, do any of you have a recommendation how to approach this task (i.e. register something and set a number of properties)?
EDIT:
Naming my class Object may have been unfortunate. As a practical example, think of Object as a property (holding an integer). Obviously there may be multiple integer properties. And imagine "active" as something akin to "should be backed up" / "should be synced with a remote process" / ...
template<typename T>
std::shared_ptr< Object<T> > RegisterAndActivate() {
std::shared_ptr< Object<T> > p = Registry::registerObject<T>();
p->activate();
return p;
}
namespace {
std::shared_ptr< Object<int> > myObject = RegisterAndActivate<int>();
}
What about freestanding function(s):
template <typename T>
std::shared_ptr<Object<T>> activate(std::shared_ptr<Object<T>> ptr) {
ptr->activate();
return ptr;
}
Then
auto x = activate(Registry::registerObject<int>());
Ok, here's what I came up with:
#include <iostream>
#include <tuple>
#include <memory>
struct Test {
bool a;
bool b;
Test() : a(false),b(false) {};
};
template<typename T, bool T::* ... props>
std::shared_ptr<T> activate(std::shared_ptr<T> inst) {
std::tie((inst.get()->*props)...) = std::make_tuple((props,true)...);
return inst;
}
int main()
{
auto t1 = activate<Test,&Test::a>(std::make_shared<Test>());
auto t2 = activate<Test,&Test::a,&Test::b>(std::make_shared<Test>());
std::cout << "t1: a = " << t1->a << ", b = " << t1->b << std::endl;
std::cout << "t2: a = " << t2->a << ", b = " << t2->b << std::endl;
}
Basically, whatever pointers to bool members you specify as template parameters, those are going to be set to true by the activate function. This way, you don't have to write many activate functions, but it is still a lot of writing because of all the Classname::classmember expressions. Working example here.
Consider the following class structure:-
class foo {
public:
int fun () {
cout << "in foo" << endl;
}
};
class bar_class1:public foo {
public:
int fun () {
cout << "in bar_class1" << endl;
}
};
class bar_class2:public foo {
public:
float fun () {
cout << "in bar_class2" << endl;
}
};
main () {
foo * foo_pointer = new bar_class1();
foo_pointer->fun();
}
The output of the above program is in foo. Is there a way, that using a pointer of type foo * which actually points to an object of type bar_class1 or bar_class2, we can call the fun function of the derived class instead of the base class? I am not able to make the fun function virtual in the base class foo since, then there is a return type conflict for function foo in the derived class bar_class2.
Here's my comments as an answer.
You cannot do that.
If that kind of polymorphism were possible, wouldn't that break horribly when code calls foo::fun (expecting an int) on an object whose actual type is bar_class2 and thus gets a float? Do you want to simply throw away type safety?
If you want different return types, sounds like you want a template. But you cannot use templates quite in the way that you want to use foo(). Static polymorphism (templates) and run time polymorphism (late binding) don't mix well. You need to redesign your oop structure.
If you absolutely hate type safety, you can sort of do this with void pointers. But for the love of Flying Spaghetti Monster, don't ever do this in c++. Please close your eyes before reading the following code to avoid exposure.
#include <iostream>
class foo {
public:
virtual void* fun() = 0;
virtual ~foo(){};
};
class bar_class1: public foo {
public:
void* fun() {
return &value;
}
private:
int value = 1;
};
class bar_class2: public foo {
public:
void* fun() {
return &value;
}
private:
float value = 1.1;
};
int main() {
foo* foo_pointer1 = new bar_class1();
foo* foo_pointer2 = new bar_class2();
// in c++ compiler must know the type of all objects during compilation
std::cout << *reinterpret_cast<int*>(foo_pointer1->fun()) << '\n';
std::cout << *reinterpret_cast<float*>(foo_pointer2->fun()) << '\n';
delete foo_pointer1;
delete foo_pointer2;
}
Perhaps similar to the existing answer, I really hope you realize changing your design is better than this mess, but I believe it's the best you're going to get. I force you to specify the return type at the callsite (e.g., someFoo->fun<int>()), since you're going to have to know it anyway, and dispatch based on that. Any funny business and you'll get an exception. Also keep in mind the performance of this is, I imagine, less than desirable.
#include <cassert>
#include <stdexcept>
#include <type_traits>
struct foo {
virtual ~foo() = default;
template<typename T, typename = typename std::enable_if<std::is_same<T, int>::value>::type, typename = void>
T fun();
template<typename T, typename = typename std::enable_if<std::is_same<T, float>::value>::type>
T fun();
};
struct bar_class1 : foo {
int fun() {
return 2;
}
};
struct bar_class2 : foo {
float fun() {
return 3.5f;
}
};
template<typename T, typename, typename Dummy>
T foo::fun() {
if (auto *p = dynamic_cast<bar_class1 *>(this)) {
return p->fun();
} else if (dynamic_cast<bar_class2 *>(this)) {
throw std::invalid_argument("Mismatching dynamic type.");
} else {
return 1;
}
}
template<typename T, typename>
T foo::fun() {
auto *p = dynamic_cast<bar_class2 *>(this);
if (dynamic_cast<bar_class1 *>(this) || !p) {
throw std::invalid_argument("Mismatching dynamic type.");
} else if (auto *p = dynamic_cast<bar_class2 *>(this)) {
return p->fun();
}
assert(false); //should never get here, but compiler doesn't know that
}
If you'd like the main function, I've written a complete sample.
To answer your question: No, late binding isn't possible without deciding the return type. ...at least not in a reasonable manner, see user2079303's great counter-example. But...
you may change your code (for example) into something like the following, using the keyword virtual and equalize the return type for instance to void:
class foo
{
public:
virtual void fun(std::ostream& out) {
out << "in foo" << std::endl;
}
};
so you can decide the output type later:
class intFoo: public foo
{
public:
void fun(std::ostream& out) {
// output an int
out << "in bar_class1. data: " << data << endl;
}
int data;
};
class floatFoo: public foo
{
public:
void fun(std::ostream& out) {
// output a float
out << "in bar_class2. data: " << data << endl;
}
float data;
};
For brevity, I double-use the output stream - now a parameter of the function fun() - function to demonstrate type-dependent portion of your derived class. In your application, the parameter will probably be of another, more useful type.
The function fun is not a virtual function since you didn't use the keyword "virtual" to decorate it. So, the compile will determine which function to call at compiling time. So, there is no way to tell the compiler to call another function because the compiler will use its static type, i.e. the variable definition type -- foo *.
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() );