Is there a C++ container that I could use or build that can contain, say, int
and string
and double
types? The problem I\'m facing is
You can use either structures, or classes or std::pair.
[edit]
For classes and structs:
struct XYZ {
int x;
string y;
double z;
};
std::vector<XYZ> container;
XYZ el;
el.x = 10;
el.y = "asd";
el.z = 1.123;
container.push_back(el);
For std::pair:
#include <pair>
typedef std::pair<int, std::pair<string, double> > XYZ;
std::vector<XYZ> container;
container.push_back(std::make_pair(10, std::make_pair("asd", 1111.222)));
If you have a finite number of items you need to store, put them in a class or structure.
If there is no limit to the items you would need to store in this container then look at a different way of doing things because the only way of doing it is by storing them as an object, and then casting them to their own type when you need to access them.
However, if any item could potentially be in the container, then you have no way of knowing what type specific items in the container are, and therefore will not be able to cast them.
If C++ contained reflection, there would possibly be a way to do this, but C++ doesn't have reflection.
What you want is called a "hetrogenious container". C++ doesn't technically support them in the STL, but Boost does.
Given that, I think you'll find your answer in this question: how-do-you-make-a-heterogeneous-boostmap
You could use a struct that contains all three.
struct Data
{
int intVal;
std::string stringVal;
double doubleVal;
};
Then you could just declare list mycontainer<Data>
and use the appropriate value, provided you know what the value type is. If not, add an addition field to the struct that tells you which of the three data types is in use.
struct Data
{
enum DATATYPE { DT_INT, DT_STRING, DT_DOUBLE } type;
int intVal;
std::string stringVal;
double doubleVal;
};
If you're worried about memory usage, you could probably use a union, though I tend to avoid using them. It might be needless paranoia on my part though.
The simplest method is of course to define a struct or class that has members of each of the types you wish to store. Josh's answer suggests Boost.Any, which will hold pretty much anything. If you want to restrict values to only those of types int
, double
, and std::string
, then the better choice would be Boost.Variant.
If you simply don't want to use Boost, then I suggest you get over your hang-ups and use it anyway. "Not Invented Here" is a self-destructive policy. But if you can't use Boost, then you can write your own variant class instead. Andrei Alexandrescu wrote a three-part series on that (part 1, part 2, part 3) a few years ago, and its design inspired the one Boost uses.
You could use (or re-implement) boost::any
and store instances of boost::any
in a container. That would be the safest, since boost::any
has probably dealt with much of the edge cases and complexity involved in solving this kind of problem in the general case.
If you want to do something quick and dirty, create a structure or perhaps a union containing members of all potential types along with an enumeration or other indicator of which type is 'active' in the object. Be especially careful with unions as they have some interesting properties (such as invoking undefined behavior if you read the wrong union member, only one of the members can be 'active' at a time, the one that was most recently written to).
I'm curious what you're doing that you need such a construct, though.