programming languages - How change class of a C++ object (implementing a variadic type) -
first off: know bad idea change object's class, i'm implementing own programming language, , has variables can contain values of type, , change type @ will, please assume i'm not beginner not understanding oo basics.
currently, implement variant variables in c. each 1 has pointer table of function pointers, containing functions setasint()
, setasstring()
etc., followed instance variables in c++. objects same size.
when variable contains string , assigns int it, manually call destructor, change table of function pointers point table used variadic int values, , then set int instance variable.
this bit hard maintain, every time add new type, have add new table of function pointers , fill out all function pointers in it. structs of function pointers seem badly type-checked, , missing fields don't lead complaints, can accidentally forget 1 pointer in list , interesting crashes. also, have repeat function pointers same in types.
i'd implement variadic types in c++ instead, lot of type-checking , inheriting default behaviours done me compiler. there safe way this?
ps - know create wrapper object , use new
allocate new object, can't have additional allocation overhead every int
variable on stack.
pps - code needs portable across linux, mac, ios , windows now, if has standard c++ solution, better.
ppps - list of types extensible, predetermined @ compile-time. base layer of language defines basic types, host application language compiled adds few more types.
usage example:
cppvariant somenum(42); // creates cppvariantint. cout << "original int: " << somenum->getasint() << " (" << somenum->getasdouble() << ")" << endl; somenum->setasint(700); // setter call. cout << "changed int: " << somenum->getasint() << " (" << somenum->getasdouble() << ")" << endl; somenum->setasdouble(12.34); // calls destructor on cppvariantint , constructor on cppvariantdouble(12.34). cout << "converted double: " << somenum->getasint() << " (" << somenum->getasdouble() << ")" << endl; // getasint() on cppvariantdouble() rounds, or whatever.
(imagine beyond double , int, there other types in future, strings or booleans, caller of getasint()/setasint() shouldn't have know stored as, long can converted @ runtime)
here solution based on type-erasure, union , template specializations.
i'm not sure fits requirements.
anyway, here gets:
- anything placed on dynamic storage
- no hierarchy required
you can improve further reduce amount of code, aims serve base point start.
it follows minimal, working example based on intended use in question:
#include<iostream> class cppvariant { union var { var(): i{0} {} int i; double d; }; using asintf = int(*)(var); using asdoublef = double(*)(var); template<typename from, typename to> static protoas(var); public: cppvariant(int); cppvariant(double); int getasint(); double getasdouble(); void setasint(int); void setasdouble(double); private: var data; asintf asint; asdoublef asdouble; }; template<> int cppvariant::protoas<int, int>(var data) { return data.i; } template<> int cppvariant::protoas<double, int>(var data) { return int(data.d); } template<> double cppvariant::protoas<int, double>(var data) { return double(data.i); } template<> double cppvariant::protoas<double, double>(var data) { return data.d; } cppvariant::cppvariant(int i) : data{}, asint{&protoas<int, int>}, asdouble{&protoas<int, double>} { data.i = i; } cppvariant::cppvariant(double d) : data{}, asint{&protoas<double, int>}, asdouble{&protoas<double, double>} { data.d = d; } int cppvariant::getasint() { return asint(data); } double cppvariant::getasdouble() { return asdouble(data); } void cppvariant::setasint(int i) { data.i = i; asint = &protoas<int, int>; asdouble = &protoas<int, double>; } void cppvariant::setasdouble(double d) { data.d = d; asint = &protoas<double, int>; asdouble = &protoas<double, double>; } int main() { cppvariant somenum(42); std::cout << "original int: " << somenum.getasint() << " (" << somenum.getasdouble() << ")" << std::endl; somenum.setasint(700); std::cout << "changed int: " << somenum.getasint() << " (" << somenum.getasdouble() << ")" << std::endl; somenum.setasdouble(12.34); std::cout << "converted double: " << somenum.getasint() << " (" << somenum.getasdouble() << ")" << std::endl; }
Comments
Post a Comment