- Flexibly convert between string, int, double for C Variant Class
- Variant a = 7;
- cout << "The answer is" + a.ToString() << endl; // should print "The answer is 7"
- a = "7.4";
- double &b = a.ToDouble();
- b += 1;
- cout << a.ToString() << endl; // should print 8.4
- #include <string>
- #include <iostream>
- class Variant{
- public:
- Variant(){
- data.type = UNKOWN;
- data.intVal = 0;
- }
- Variant(int v){
- data.type = INT;
- data.intVal = v;
- }
- Variant(double v){
- data.type = DOUBLE;
- data.realVal = v;
- }
- Variant(std::string v){
- data.type = STRING;
- data.strVal = new std::string(v);
- }
- //the missing copy constructor
- Variant(Variant const& other)
- {
- *this = other;// redirect to the copy assignment
- }
- ~Variant(){
- if(STRING == data.type){
- delete data.strVal;
- }
- }
- Variant& operator = (const Variant& other){
- if(this != &other)
- {
- if(STRING == data.type){
- delete data.strVal;
- }
- switch(other.data.type){
- case STRING:{
- data.strVal = new std::string(*(other.data.strVal));
- data.type = STRING;
- break;
- }
- default:{
- memcpy(this, &other, sizeof(Variant));
- break;
- }
- }
- }
- return *this;
- }
- Variant& operator = (int newVal){
- if(STRING == data.type){
- delete data.strVal;
- }
- data.type = INT;
- data.intVal= newVal;
- return *this;
- }
- Variant& operator = (double newVal){
- if(STRING == data.type){
- delete data.strVal;
- }
- data.type = DOUBLE;
- data.realVal= newVal;
- return *this;
- }
- Variant& operator = (std::string& newVal){
- if(STRING == data.type){
- delete data.strVal;
- }
- data.type = STRING;
- data.strVal= new std::string(newVal);
- return *this;
- }
- operator int&() {
- if(INT == data.type)
- {
- return data.intVal;
- }
- //do type conversion if you like
- throw std::runtime_error("bad cast");
- }
- operator double&() {
- if(DOUBLE == data.type){
- return data.realVal;
- }
- //do type conversion if you like
- throw std::runtime_error("bad cast");
- }
- operator std::string&() {
- if(STRING == data.type){
- return *data.strVal;
- }
- throw std::runtime_error("bad cast");
- }
- private:
- enum Type{
- UNKOWN=0,
- INT,
- DOUBLE,
- STRING
- };
- struct{
- Type type;
- union
- {
- int intVal;
- double realVal;
- std::string* strVal;
- };
- } data;
- };
- int main(){
- Variant v("this is string");//string
- v=1;//int
- v=1.0;//double
- v=std::string("another string");//
- Variant v2; //unkown type
- v2=v;//string
- std::cout << (std::string&)v2 << std::endl;
- return 0;
- }
- class Variant
- {
- private:
- enum StoreType
- {
- Integer,
- Float,
- String,
- }
- store_type;
- union
- {
- int * as_integer;
- double * as_double;
- std::string * as_string;
- }
- store_pointer;
- // convert to type
- void integer_to_double();
- void integer_to_string();
- void double_to_integer();
- void double_to_string();
- void string_to_integer();
- void string_to_double();
- public:
- ...
- int & ToInt()
- {
- switch (store_type)
- {
- case Integer: break;
- case Double: double_to_integer(); break;
- case String: string_to_integer(); break;
- }
- return * as_integer;
- }
- ...
- }
- class Variant {
- enum internaltype {stringtype, inttype, doubletype} curtype;
- std::string strdata; //can't be in union
- union {
- int intdata;
- double doubledata;
- };
- public:
- Variant() :curtype(inttype) {}
- Variant(const std::string& s) : curtype(stringtype), strdata(s) {}
- Variant(int i) : curtype(inttype) {intdata = i;}
- Variant(double d) : curtype(doubletype) {doubledata = d;}
- std::string& ToString() {
- std::stringstream ss;
- switch(curtype) {
- case inttype:
- ss << intdata;
- ss >> stringdata;
- break;
- case doubletype:
- ss << doubledata;
- ss >> stringdata;
- break;
- }
- curtype = stringtype;
- return &strdata;
- }
- int& ToInt() {/*much the same*/}
- double& ToDouble() {/*much the same*/}
- };
- #include <boost/any.hpp>
- #include <boost/lexical_cast.hpp>
- #include <string>
- #include <typeinfo>
- class Variant
- {
- boost::any value;
- public:
- Variant(int n): value(n) {}
- Variant(double d): value(d) {}
- Variant(const std::string& s): value(s) {}
- Variant(const char* s): value(std::string(s)) {} //without this, string literals create ambiguities
- int& ToInt() { return convert<int>();}
- double& ToDouble() { return convert<double>(); }
- std::string& ToString() { return convert<std::string>(); }
- private:
- template <class T>
- T& convert()
- {
- if (typeid(T) != value.type()) { //otherwise no conversion required
- if (typeid(int) == value.type()) {
- value = boost::lexical_cast<T>(boost::any_cast<int>(value));
- }
- else if (typeid(double) == value.type()) {
- value = boost::lexical_cast<T>(boost::any_cast<double>(value));
- }
- else if (typeid(std::string) == value.type()) {
- value = boost::lexical_cast<T>(boost::any_cast<std::string>(value));
- }
- }
- return *boost::any_cast<T>(&value);
- }
- };
- #include <iostream>
- using namespace std;
- int main()
- {
- Variant a = 7;
- cout << "The answer is" + a.ToString() << endl; // should print "The answer is 7"
- a = "7.4";
- double &b = a.ToDouble();
- b += 1;
- cout << a.ToString() << endl; // should print 8.4
- }
- class Variant
- {
- private:
- enum data_type {
- ...
- };
- data_type variant_type;
- union Data {
- char *string;
- int integer;
- double dbl;
- } data;
- public:
- Variant(const int data);
- Variant(const double data);
- Variant(const char *data);
- // I think that implementation of the constructors should be pretty straight forward.
- int ToInt() const;
- double ToDouble() const;
- std::string ToString() const;
- };
- class Variant
- {
- private:
- char data_string[16384];
- public:
- Variant(const int data);
- Variant(const double data);
- Variant(const char *data);
- // I think that implementation of the constructors should be pretty straight forward.
- int ToInt() const;
- double ToDouble() const;
- std::string ToString() const;
- };