A vector of things

I have this:

1
2
3
4
5
6
template < typename T >
struct foo
{
    std::string name;
    T value;// can be string, color, rect...
};


And now i need a vector of these foo's, but each item inserted will have different type of foo::value.

Now i can't create that vector if i dont pass template argument.
std::vector< foo<?> > vfoos;

Any idea how to achieve this?
Last edited on
Can't you have a vector for each type?
No. I would like it to be in one place.
Last edited on
No. I would like it to be in one place.


You could have a vector of boost.any http://www.boost.org/doc/libs/1_51_0/doc/html/any.html

You could also create an interface, which your foo struct will implement, have the vector hold pointers to this interface. As it stands, foo<color>, foo<record> are completely different unique types and cannot be mixed within the same vector.

It just depends on what you want/need/can get away with and what pros/cons you are willing to accept. With this latter approach there will need to be some casting...

This is just for an idea, it is very simple, maybe too simple..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct iFoo{
	virtual string GetName()const=0;

	virtual ~iFoo(){}
};

template<typename T>
struct foo : iFoo{
	string GetName()const{return Name;}
	string Name;
	T Value;
};

vector<iFoo *> vfoos;// Or...
vector<std::unique_ptr<iFoo>> vfoos; // Or.. shared.. whatever you need. 
closed account (zb0S216C)
A variant?

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
struct variant
{
	enum active_type
	{
		at_float,
		at_int,
		at_char
	} active_;

	variant(float const value = 0.0f) : data_(value) { }
	variant(int const value = 0.0f) : data_(value) { }
	variant(char const value = 0.0f) : data_(value) { }

	union data
	{
		data(float const value = 0.0f) : float_(value) { }
		data(int const value = 0.0f) : int_(value) { }
		data(char const value = 0.0f) : char_(value) { }

		float float_;
		int int_;
		char char_;
	} data_;

	variant &operator = (float const value)
	{
		this->data_.float_ = value;
		this->active_ = at_float;
		return(*this);
	}

	variant &operator = (int const value)
	{
		this->data_.int_ = value;
		this->active_ = at_int;
		return(*this);
	}

	variant &operator = (char const value)
	{
		this->data_.char_ = value;
		this->active_ = at_char;
		return(*this);
	}
};

std::ostream &operator << (std::ostream &stream, variant const &var)
{
    switch(var.active_)
    {
        case variant::at_float:
            stream << var.data_.float_;
            break;

        case variant::at_int:
            stream << var.data_.int_;
            break;

        case variant::at_char:
            stream << var.data_.char_;
            break;
    }
}

Wazzak
Thanks everybody.

@Framework
I like your idea.

EDIT: Looks like i cannot have std::string in a union. VS2012 is throwing me an error.
Last edited on
closed account (zb0S216C)
That's a downside to unions: a data member cannot have a default constructor, copy-constructor, move-constructor, copy-assignment operator, move-assignment operator, or destructor. For built-in types, though, it's quite nifty.

Wazzak
Last edited on
In C++11 you can have std::string in a union.
> That's a downside to unions: a data member cannot have a default constructor ...

Not really. Just that if any non-static data member of a union has a non-trivial copy constructor, the copy constructor of the union is implicitly deleted unless a user-defined copy constructor is provided. And likewise for the other foundation operations.

Use a boost::variant<> perhaps?
http://www.boost.org/doc/libs/1_51_0/doc/html/variant.html

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
#include <string>
#include <boost/variant.hpp>
#include <complex>
#include <vector>
#include <iostream>

struct foo
{
    std::string name ;
    boost::variant< int, std::string, std::complex<double> > value ;

    foo( const std::string& n, int v ) : name(n), value(v) {}
    foo( const std::string& n, const std::string& v ) : name(n), value(v) {}
    foo( const std::string& n, double re, double im )
                          : name(n), value( std::complex<double>(re,im) ) {}

    // ...
};

int main()
{
    std::vector<foo> vfoos ;
    vfoos.emplace_back( "abc", 123 ) ;
    vfoos.emplace_back( "efghi", "jklmno" ) ;
    vfoos.emplace_back( "pqrs", 4.56, 78.9 ) ;
    for( const foo& f : vfoos ) std::cout << f.name << ": " << f.value << '\n' ;
}
closed account (zb0S216C)
@JLBorges: Does that apply only to C++11?

Wazzak
That we can have a std::string as a non-static member variable of a union came with C++11.

boost::variant<> does not require C++11 - it has been around for a long time.
Topic archived. No new replies allowed.