return any type without boost::any

Pages: 12
Thats common situation, when working with a db a user can choose some data and pass them for further processing to functions. So, type of chosen data depends on user's choice and not known during a compilation. Could you please point me on how to properly organize classes structure to be able to temporarily store the data in a container of appropriate type and later pass them to functions of appropriate type. I'm stalled on the following:
vector<Base*> holds pointers to Derived<T>

class Base{
public:
virtual vector<bool>* ret_b();
???? to return vector<T>* t
};

template<typename T>
class Derived : public Base{
public:
vector<bool>* ret_b();
???? to return vector<T>* t
private:
vector<bool>* b;
vector<T>* t;
};

How to store type information to be able to cast Base* to Derived* of appropriate type i.e. Derived<int>*, Derived<vector<bool> >* ?
How to organize classes, so I'll be able to return vector<int>* vector<bool>*.... or reference to them to functions? Shure that was resolved prior introduction of boost::any. I have a big gap in my knowledge.
Google was not helpful:-(

Kind regards,
s.
I don't quite understand what you want to do. But in your example I think Base would also need to be a template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
class Base
{
public:
    virtual vector<bool>* ret_b();
    vector<T>* t; // now vector knows its type
};

template<typename T>
class Derived : public Base<T> // pass type info to base
{
public:
    vector<bool>* ret_b(); // override Base class
    // vector<T>* t // already defined in Base, not needed here
};
Galik (458) Thank U that's trivial.
I want to know how a container of containers of types which are unknown on compilation time could be implemented without boost::any.

<<Base would also need to be a template>>

I could not declare vector<Base<T>*> as containers are homogeneous.

A user selects data and they are stored for exmpl in Derived<int> and Derived<double>. the program puts Derived<int>* and Derived<double>* into vector<Base*>. If I know types and order they are stored into vector<Base*>, I can make dynamic_cast<Derived<int>* (Base*) for Deriver<int>*, dynamic_cast<Derived<double>* (Base*) for Deriver<double>*, but in my case I dont know what types, in what order and how many of them will be stored into vector<Base*> , so I dont know to what type I should cast concrete record of Base*. Simple polymorphic solution doesn't work. I need somehow to store type information to definitely know that concrete record in vector<Base*> present concrete type of Derived<>*, but I could not figure out how to make this.

If you want an element in a vector to be of any of a limited set of types, you can create your own type system by creating a single class that contains information about the type it stores. For example,
1
2
3
4
5
6
7
8
9
10
11
12
class Anything{
    enum Type{
        INTEGER,
        REAL,
        STRING
    }
    union{
        int i;
        double d;
        std::string *s;
    };
};


If you want total freedom to add types without recompiling, you'd have to make the vector store pointers to buffers, the first few bytes of which determine the type of what comes next.
1
2
3
4
5
6
7
8
9
10
11
12
std::vector<uchar *> v;
switch (get_type(v[i]){
    case INTEGER:
        get_integer(v[i]);
        break;
    case REAL:
        get_real(v[i]);
        break;
    case STRING:
        get_string(v[i]);
        break;
}
The user has to provide definitions of all functions that modify the buffer, but the vector itself can remain unchanged.
this is relevant to my interests, I've been trying off and on to figure out how to do this efficently for about a month
helios, Thank you.
How can I declare the function which will hold a/m switch case? Of what return type?
Seraphimsan

the same for me :-(
In general - question is about: how to store a type ifo and give it back for dynamic_cas<T> (x). I think we could not use static polymorphism at run-time. So, how?
I can see better what I think you are trying to achieve now. I don't think all of what you want is possible. At the end of the day the piece of code that access the typed containers MUST know what the type is (read from the base class).

So it is the code that accesses the container that must supply the type information for the dynamic cast.

Here is something that might fulfil some of what you are looking for:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <typeinfo>
#include <vector>
#include <iostream>

template<typename T> struct other_t;

struct base_t
{
    const std::type_info& id;
    base_t(const std::type_info& id) : id(id){}

    template<typename T>
    other_t<T>& get_as(other_t<T>&)
    {
    	return reinterpret_cast<other_t<T>&>(*this);
    }
};

template<typename T>
struct other_t : public base_t
{
	other_t(): base_t(typeid(T)) {}
	std::vector<T> list;
};

int main()
{
	// list of various typed lists
	std::vector<base_t*> list;

	// int list
	other_t<int> other_i;
	other_i.list.push_back(1);
	other_i.list.push_back(5);
	other_i.list.push_back(9);

	list.push_back(&other_i);

	// float list
	other_t<float> other_f;
	other_f.list.push_back(1.7f);
	other_f.list.push_back(9.9f);
	other_f.list.push_back(2.1f);

	list.push_back(&other_f);

	// go through each typed list in the list
	for(size_t i(0); i < list.size(); ++i)
	{
		if(list[i]->id == typeid(int)) // is it int list?
		{
			std::cout << "\nint list:\n";

			other_t<int>& oi = list[i]->get_as(oi);
			for(size_t i(0); i < oi.list.size(); ++i)
			{
				std::cout << oi.list[i] << std::endl;
			}
		}
		else if(list[i]->id == typeid(float)) // is it float list?
		{
			std::cout << "\nfloat list:\n";

			other_t<float>& of = list[i]->get_as(of);
			for(size_t i(0); i < of.list.size(); ++i)
			{
				std::cout << of.list[i] << std::endl;
			}
		}

	}

	return 0;
}

int list:
1
5
9

float list:
1.7
9.9
2.1
Last edited on
saraksh wrote:
Simple polymorphic solution doesn't work.

Why? Take a look at this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <iostream>
#include <string>
#include <vector>
using namespace std;

class DataType
{
public:

    virtual void operator=(int) {cerr << "type mismatch...\n";}
    virtual void operator=(string) {cerr << "type mismatch...\n";}

    virtual operator int() {cerr <<"type mismatch...\n"; return 0;}
    virtual operator string() {cerr <<"type mismatch...\n"; return "(error)";}

    virtual void stream_out(ostream & os)=0;
    virtual void stream_in(istream & is)=0;

    friend ostream & operator<<(ostream & os,DataType & dt)
    {
        dt.stream_out(os);
        return os;
    }

    friend istream & operator>>(istream & is,DataType & dt)
    {
        dt.stream_in(is);
        return is;
    }

    virtual void do_something()=0;
    virtual void do_int_thing(){}
    virtual void do_string_thing(){}
    //...
};

class Integer: public DataType
{
private:

    int data;

public:

    Integer(int d=0):data(d) {}

    void operator=(int d) {data=d;}
    operator int() {return data;}

    void stream_out(ostream & os) {os<<data;}
    void stream_in(istream & is) {is>>data;}

    void do_something()
    {
        cout << "doing something with the int " << data << "..." << endl;
    }

    void do_int_thing()
    {
        cout << "doing int thing with the int " << data << "..." << endl;
    }
};

class String: public DataType
{
private:

    string data;

public:

    String(string d="(empty)"):data(d) {}

    void operator=(string d) {data=d;}
    operator string() {return data;}

    void stream_out(ostream & os) {os<<data;}
    void stream_in(istream & is) {is>>data;}

    void do_something()
    {
        cout << "doing something with the string " << data << "..." << endl;
    }

    void do_string_thing()
    {
        cout << "doing string thing with the string " << data << "..." << endl;
    }
};

void cleanup(vector<DataType*> & container)
{
    vector<DataType*>::iterator it;

    for (it=container.begin(); it!=container.end(); it++)
        delete *it;
}

int main()
{
    vector<DataType*> container;

    container.push_back(new Integer);
    container.push_back(new Integer(5));
    container.push_back(new String);
    container.push_back(new String("asdf"));

    int i;
    for (i=0; i<4; i++)
        cout << "*container[" << i << "]=" << *container[i] << endl;

    int my_int;

    cout << "\nattempting to put an Integer to an int..." << endl;
    my_int=*container[1];
    cout << "my_int=" << my_int << endl;

    cout << "\nattempting to put a String to an int..." << endl;
    my_int=*container[2];
    cout << "my_int=" << my_int << endl;

    cout << "\nattempting to put an int to an Integer..." << endl;
    *container[0]=7;
    cout << "*container[0]=" << *container[0] << endl;

    cout << "\nattempting to put an int to a String..." << endl;
    *container[3]=6;
    cout << "*container[3]=" << *container[3] << endl;

    cout << "\nputting a string to a String using cin..." << endl;
    cout << "enter a string: ";
    cin >> *container[2];
    cout << "*container[2]=" << *container[2] << endl;

    cout << "\nhit enter to continue...";
    while(cin.get()!='\n');
    while(cin.get()!='\n');

    cout << "\nok, now let's do some things with each element..." << endl;
    for (i=0; i<4; i++)
    {
        container[i]->do_something();
        container[i]->do_int_thing();
        container[i]->do_string_thing();
    }

    cleanup(container);

    cout << "\nhit enter to quit...";
    cin.get();
    return 0;
}
Last edited on
m4ster r0shi you sure the master of long-winded implementations.
Hahahahaha, no doubt! But look at my main, it's pretty small if you omit the output statements. I've been wondering if you'd jump in saying that this can be done with the boost library with only 3-5 lines of code... :D
Well, ok, every program I've ever written has one line of code in main():

1
2
3
int main() {
   rest_of_program();
}


OP already said not to use boost::any...

The only other boost answer I have is boost::variant, but you have to know the
set of types at compile time, and it has to be relatively small.
Mmmm... Are you telling the truth about your programs? I'd swear it's way more likely that they look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void boost_rulez()
{
    /* This function does nothing.
     * It is here just to remind
     * to all of you that for every
     * problem you have, boost
     * has a solution simpler and
     * faster than anything you
     * will ever see in your wildest dreams...
     */
}

int main() {
    boost_rulez();
    rest_of_program();
}
m4ster r0shi you sure the master of long-winded implementations.
Never mind me. Just passing through.
http://www.cplusplus.com/forum/lounge/24912/#msg132446
... (I'm ignoring you)
Well, although it breaks my heart to say so... You can do it in a simpler way, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
#include <string>
#include <vector>
using namespace std;

class DataType
{
public:
    virtual void * get_data()=0;
    virtual int type() {return 0;}
};

class Integer: public DataType
{
private:
    int data;

public:
    Integer(int d=0):data(d) {}

    void * get_data() {return &data;}
    int type() {return 1;}
};

class String: public DataType
{
private:
    string data;

public:
    String(string d="(empty)"):data(d) {}

    void * get_data() {return &data;}
    int type() {return 2;}
};

void do_stuff(int * n)
{
    cout << "doing int stuff with " << *n << "..." << endl;
}

void do_stuff(string * s)
{
    cout << "doing string stuff with " << *s << "..." << endl;
}

void cleanup(vector<DataType*> & container)
{
    vector<DataType*>::iterator it;

    for (it=container.begin(); it!=container.end(); it++)
        delete *it;
}

int main()
{
    vector<DataType*> container;

    container.push_back(new Integer);
    container.push_back(new Integer(5));
    container.push_back(new String);
    container.push_back(new String("asdf"));

    int i;
    int type;

    for (i=0; i<4; i++)
    {
        type=container[i]->type();

        switch (type)
        {
            case 1:
            do_stuff((int*)container[i]->get_data());
            break;

            case 2:
            do_stuff((string*)container[i]->get_data());
            break;
        }
    }

    cleanup(container);

    cout << "\nhit enter to quit...";
    cin.get();
    return 0;
}
Last edited on
You're right m4ster r0shi -- I lied. Actually, most of my programs look like this:

1
2
3
4
5
//#include <every boost library imaginable>

int main( int argc, char* argv[] ) {
    return boost::bind( &rest_of_program, argc, argv )();
}


Seriously though, I like short (non polymorphic) solutions not just because of their elegance,
but also because the less details I have to remember, the better.

I wrote a "simple" system using inheritance where I could build packets of a layered protocol
in place. It truly was simple. You have a buffer. You construct the top-most protocol object
on the buffer and fill out its fields. Then you construct the next protocol layer object on the
buffer and fill out its fields, and so forth. When I wrote it, it was simple. I could add new
messages in a minute.

Several years later, I look back at all the inheritance, and its no longer that simple to me.
I don't remember all the details of what was going through my mind.

Several years ago, I converted that code to use serialization to build the packets. All
the "internal" base classes went away, leaving only one non-inherited class for each
message. Even now, I think I can remember all the details, because, well, there aren't
really many details to remember.
Well, although it breaks my heart to say so... You can do it in a simpler way, like this:

With this technique you will end up with functions returning void. What to do if I want to return vector<T>* ?
Take a look at what Galik suggested above.

EDIT: But, if you want to store different types to different containers, why don't you just have one container for every type you'll use? Then, when the user enters an int push it back to the int container, when he enters a string push it back to the string container etc... I mean, why would you need a container to contain these containers?
Last edited on
Take a look at what Galik suggested above.

Many thanks to Galik, I'm playing with his code now. The problem is that I'm getting data from various db tables and need separate containers even for same data type. If user chose 3 fields from db with type int and 2 with bool, I have to create 7 objects holding pointer to vector with appropriate data type and consequently pass these vectors to functions for further processing.
Pages: 12