I have briefly looked around various c++ sites and text books. But none of them have had anything related to what I was looking for.
What I want is a list in c++ which can contain int, string and int array variables within it. But before I spend hours playing around with some code, I was wondering if anyone knew if such a thing actually exists? I'm not asking for code to be shown to me, if it is possible, I will attempt it, and then ask about any issues I have with it.
Thanks
Your best bet is boost::variant. Remember - I didn't tell you it will be easy.
Usage will be simple:
typedef boost::variant<...my necessary types...> MyVariant;
std::list<MyVariant> myList;
In case you meant an object that can contain int, string and arrays as separate objects, not as one (like union) -- I think you should take a look at C++11 tuples
, and use them in list.
It might be unsafe to put different types of objects/data in single list.
But if it the requirement, then why not derive new class from std::list with combination of keeping track of types being inserted into list using aproach mentioned in above answer.
You can also create a struct using union or void pointer.
enum varType
{
vt_int,
vt_float,
vt_string
}
class myVariant
{
private:
void* mVariable;
varType mType;
};
or also,
class myVariant2
{
private:
union
{
float fValue;
int iValue;
std::string* sValue;
};
varType mType;
}
It's not nice and would require casting heavily, but if you don't like using other libraries for such small task, this might be of help.
Edit1: You will need getStringValue, getFloatValue getIntValue functions.
Edit2: You can safely use this classes in std::list.
Edit3: You need to call destructor of std::string (if the variable is a string) yourself.
Related
Traditionally, I've programmed in c++ and Java, and I'm now beginning to learn ruby.
My question then is, how do languages like ruby internally implement their array and hash data structures in such a way that they can hold any type at the same time? I know that in Java, the fact that every class is derived from object, could be one way to implement this, but I was wondering if there was another way. For example, in c++, if I wanted to implement a dynamic array that could simultaneously hold multiple types of values (of no relation), how could I do this?
To clarify, I'm not referring to generic programming or templates, as those simply create a new collection interface for a type. I'm referring to a structure such as this:
array = [1, "hello", someClass];
Most of them do roughly the same as you'd get in C++ by creating a vector (or list, deque, etc.) of boost::any, or something similar.
That is to say, they basically attach some tag to each type of object as it's stored in memory. When they store an object, they store the tag. When they read an object, they look at the tag to figure out what kind of object that is. Of course, they also handle most of this internally, so you don't have to write the code to figure out what kind of object you've just retrieved from the collection.
In case it's not clear: the "tag" is just a unique number assigned to each type. If the system you're dealing with has primitive types, it'll normally pre-assign a type number to each of them. Likewise, each class you create gets a unique number assigned to it.
To do that in C++, you'd normally create a central registry of tags. When you register a type, you receive a unique number back that you use to tag objects of that type. When a language supports this directly, it automates the process of registering types and choosing a unique tag for each.
Although this is probably the most common method of implementing such things, it's definitely not the only one. Just for example, it's also possible to designate specific ranges of storage for particular types. When you allocate an object of a given type, it's always allocated from that type's address range. When you create a collection of "objects", you're really not storing the objects themselves, but instead storing something that contains the address of the object. Since objects are segregated by address you can figure out the type of the object based on the value of the pointer.
In the MRI interpreter, a ruby value is stored as a pointer type which points to a data structure storing the class of the value and any data associated with the value. Since pointers are always the same size, (sizeof(unsigned long) usually), it is possible. To answer your question about C++, it is impossible in C++ to determine the class of an object given it's location in memory, so it wouldn't be possible unless you had something like this:
enum object_class { STRING, ARRAY, MAP, etc... };
struct TaggedObject {
enum object_class klass;
void *value;
}
and passed around TaggedObject * values. That is pretty much what ruby does internally.
There are many ways to do that :-
You can define a common interface for all the elements and make a container of those. For example:
class Common { /* ... */ }; // the common interface.
You can use container of void* :-
vector<void*> common; // this would rather be too low level.
// you have to use cast very much.
And then the best approach I think is using an Any class, such as Boost::Any :-
vector<boost::any> v;
You're looking for something called type erasure. The simplest way to do this in C++ is with boost::any:
std::vector<boost::any> stuff;
stuff.push_back(1);
stuff.push_back(std::string("hello"));
stuff.push_back(someClass);
Of course with any, you're extremely limited in what you can do with your stuff since you have to personally remember everything you put into it.
A more common use-case of heterogeneous containers might be a series of callbacks. The standard class std::function<R(Args...)> is, in fact, a type-erased functor:
void foo() { .. }
struct SomeClass {
void operator()() { .. }
};
std::vector<std::function<void()>> callbacks;
callbacks.push_back(foo);
callbacks.push_back(SomeClass{});
callbacks.push_back([]{ .. });
Here, we're adding three objects of different types (a void(*)(), a SomeClass, and some lambda) to the same container - which we do by erasing the type. So we can still do:
for (auto& func : callbacks) {
func();
}
And that will do the right thing in each of the three objects... no virtuals needed!
Others have explained ways you can do this in C++.
There are various ways to solve this problem. To answer your question about how does languages such as Ruby solve this, without going into details of exactly how Ruby solves it, they use a structure that contains type information. For example, we could do that in C++ something like this:
enum TypeKind { None, Int, Float, String }; // May need a few more?
class TypeBase
{
protected:
TypeKind kind;
public:
TypeBase(TypeKind k) : kind(k) { }
virtual ~TypeBase() {};
TypeKind type() { return kind; }
};
class TypeInt : public TypeBase
{
private:
int value;
public:
TypeInt(int v) : value(v), TypeBase(Int) {}
};
class TypeFloat : public TypeBase
{
private:
double value;
public:
TypeFloat(double v) : value(v), TypeBase(Float) {}
};
class TypeString : public TypeBase
{
private:
std::string value;
public:
TypeString(std::string v) : value(v), TypeBase(String) {}
};
(To make it useful, we probably need some more methods for the TypeXxx class, but I don't feel like typing for another hour... ;) )
And then somewhere, it determines the type, e.g.
Token t = getNextToken();
TypeBase *ty;
if (t.type == IntegerToken)
{
ty = new(TypeInt(stoi(t.str));
}
else if (t.type == FloatToken)
{
ty = new(TypeFloat(stod(t.str));
}
else if (t.type == StringToken)
{
ty = new(TypeString(t.str));
}
Of course, we'd also need to deal with variables and various other scenarios, but the essence of it is that the language can keep track of (and sometimes mutate) the value that is stored.
Most languages in the general category where Ruby, PHP, Python, etc are, will have this sort of mechanism, and all variables are stored in some sort of indirect way. The above is just one possible solution, I can think of at least half a dozen other ways to do this, but they are variations on the theme of "store data together with type information".
(And by the way, boost::any also does something along the lines of the above, more or less....)
In Ruby, the answer is rather simple: that array doesn't contain values of different types, they are all of the same type. They are all objects.
Ruby is dynamically typed, the idea of an array that is statically constrained to only hold elements of the same type doesn't even make sense.
For a statically typed language, the question is, how much do you want it to be like Ruby? Do you want it to be actually dynamically typed? Then you need to implement a dynamic type in your language (if it doesn't already have one, like C♯’s dynamic).
Otherwise, if you want a statically typed heterogenous list, such a thing is usually called an HList. There's a very nice implementation for Scala in the Shapeless library, for example.
I am working on a modular data logger that allows one to log data of different types. At the moment I made a File class that is a template. In order to declare an object of such a class one would do as such: File<double> f("filename.txt") or File<float> f("filename.txt"). I want to be able to store objects that were declared with double or float as template parameters in one vector. Is it possible to do something like that? I have tried a method online that uses a union as such:
union typ {
int int_dat;
double double_dat;
float float_dat;
}
and allows me to declare a vector as such: vector<File<typ> >. However, this gives me linker errors. Is there a easier, cleaner way to attempt this? The entire project in question is here
EDIT: follow up to this. How would one circumvent the issue surrounding the fact that if I conduct such operations:
std::vector<File<typ> > files;
File<typ> f("test.txt");
files.push_back(f);
files.at(0) << 35.4;
it causes a compile time error which I comprehended as what I'm guessing is: 35.4 is not of the type typ and cannot be used in the operation <<. How would one bypass such an error?
I think your vector of unions might have some issues. I haven't looked at your full code, but refer to this:
Questions about vector, union, and pointers in C++
The following should work (see http://codepad.org/TyrURyar)
#include <vector>
union type {
int int_dat;
double double_dat;
float float_dat;
};
template <typename T>
class Foo {
T t;
};
void foo2() {
std::vector<Foo<type> > x;
// NOTE: In pre-C++11, space is required between the >'s
}
Use Boost::Variant, if you can. It's a cleaner option. Unions can be used, but you should write and read from the same member if you don't want to end up with undefined behaviour i.e. it involves book keeping, which anyways Variant does for you automatically.
This is my (maybe a little bit weird) thought, suppose I want to define a std::set object to contain some stuff for later use, but unfortunately I'm not sure which type will be passed to std::set<not-sure> as template arg, and this not-sure type will be determined through a string, like this:
class X {
public:
foo()
{
char not_sure_type[20];
scanf("%s", not_sure_type);
if (strcmp(not_sure_type, "int"))
// then std::set<int>
else if (// "char")
// then std::set<char>
}
private:
void * _set;
};
This way, I can determine that std::set<int> will be instantiated or not, right? But how can I tell _set that you should point to a std::set<int>? Without knowing that, either I cannot use static_cast to cast _set from void * to std::set<int>*, back and forth.
So can I save the std::set<int> just like an data member for later use?
Any idea is appreciated.
If you will know the the type of the set element at run-time (based on a say string), you could maybe store a pointer to an abstract type into the set (set), and then use an Abstract Factory in the constructor of the class that holds the std::set to instantiate the actual Concrete Types for the elements during run-time based on the provided string.
The problem is in using raw pointers here, since you will need to do the cleanup within the class that has std::set. Since you want to use std::set, make sure that your Concrete Type for the element is Comparable. Not sure if this is the right way to go though.. you said to throw in ideas...
sounds to me like you are considering using c++ as a weak type language, such as python. sure there could be workarounds like using some abstract base class etc. but the bottom line I think is that defining the type at run time is against the paradigm of c++..
I am trying to create something like a list. However, different instances of the list may have a different number of entries, and the type of entry is based on input given by the user. For example, the user states that they want the structure of each entry in the list to contain an int id, a std::string name, a double metricA, and a long metricB. Based on this input, the following is created:
struct some_struct {
int id;
std::string name;
double metricA;
long metricB;
}
list<some_struct> some_list;
The user input may be read from a file, input on the screen, etc. Additionally, their are a variable number of entries in some_struct. In other words, it may have the entries listed above, it may have just 2 of them, or it may have 10 completely different ones. Is there someway to create a struct like this?
Additionally, being able to apply comparison operators to each member of some_struct is a must. I could use boost::any to store the data, but that creates issues with comparison operators, and also incurs more overhead than is ideal.
C++ is a strongly-typed language, meaning you have to declare your data structure types. To that end you cannot declare a struct with arbitrary number or type of members, they have to be known upfront.
Now there are ways, of course, to deal with such issues in C++. To name a few:
Use a map (either std::map or std::unordered_map) to create a "table" instead of a structure. Map strings to strings, i.e. names to string representation of the values, and interpret them to your heart.
Use pre-canned variant type like boost::any.
Use polymorphism - store pointers to base in the list, and have the virtual mechanism dispatch operations invoked on the values.
Create a type system for your input language. Then have table of values per type, and point into appropriate table from the list.
There probably as many other ways to do this as there are C++ programmers.
There are many ways to solve the problem of data structures with varying members and which is best depends a lot on how exactly it is going to be used.
The most obvious is to use inheritance. You derive all your possibilities from a base class:
struct base_struct {
int id;
std::string name;
};
list<base_struct*> some_list;
struct some_struct : public base_struct {
double metricA;
};
struct some_other_struct : public base_struct {
int metricB;
};
base_struct *s1 = new some_struct;
s1->id = 1;
// etc
base_struct *s2 = new some__other_struct;
s2->id = 2;
// etc
some_list.push_back(s1);
some_list.push_back(s2);
The tricky bit is that you'll have to make sure that when you get elements back out, you case appropriately. dynamic_cast can do this in a type-safe manner:
some_struct* ss = dynamic_cast<some_struct*>(some_list.front());
You can query the name before casting using type_info:
typeid(*some_list.front()).name();
Note that both these require building with RTTI, which is usually OK, but not always as RTTI has a performance cost and can bloat your memory footprint, especially if templates are used extensively.
In a previous project, we dealt with something similar using boost any. The advantage of any is that it allows you to mix types that aren't derived from one another. In retrospect, I'm not sure I'd do that again because it made the code a bit too apt to fail at runtime because type checking is being deferred until then. (This is true of the dynamic_cast approach as well.
In the bad old C days, we solved this same problem with a union:
struct base_struct {
int id;
std::string name;
union { // metricA and metricB share memory and only one is ever valid
double metricA;
int metricB;
};
};
Again, you have the problem that you have to deal with ensuring that it is the right type yourself.
In the era before the STL, many container systems were written to take a void*, again requiring the user to know when to cast. In theory, you could still do that by saying list<void*> but you'd have no way to query the type.
Edit: Never, ever use the void* method!
I ended up using a list with a boost::variant. The performance was far better than using boost::any. It went something like this:
#include <boost/variant/variant.hpp>
#include <list>
typedef boost::variant< short, int, long, long long, double, string > flex;
typedef pair<string, flex> flex_pair;
typedef list< flex_pair > row_entry;
list< row_entry > all_records;
I'm trying to teach myself C++, and one of the traditional "new language" exercises I've always used is to implement some data structure, like a binary tree or a linked list. In Java, this was relatively simple: I could define some class Node that maintained an instance variable Object data, so that someone could store any kind of object in every node of the list or tree. (Later I worked on modifying this using generics; that's not what this question is about.)
I can't find a similar, idiomatic C++ way of storing "any type of object." In C I'd use a void pointer; the same thing works for C++, obviously, but then I run into problems when I construct an instance of std::string and try to store it into the list/tree (something about an invalid cast from std::string& to void*). Is there such a way? Does C++ have an equivalent to Java's Object (or Objective-C's NSObject)?
Bonus question: If it doesn't, and I need to keep using void pointers, what's the "right" way to store a std::string into a void*? I stumbled upon static_cast<char*>(str.c_str()), but that seems kind of verbose for what I'm trying to do. Is there a better way?
C++ does not have a base object that all objects inherit from, unlike Java. The usual approach for what you want to do would be to use templates. All the containers in the standard C++ library use this approach.
Unlike Java, C++ does not rely on polymorphism/inheritance to implement generic containers. In Java, all objects inherit from Object, and so any class can be inserted into a container that takes an Object. C++ templates, however, are compile time constructs that instruct the compiler to actually generate a different class for each type you use. So, for example, if you have:
template <typename T>
class MyContainer { ... };
You can then create a MyContainer that takes std::string objects, and another MyContainer that takes ints.
MyContainer<std::string> stringContainer;
stringContainer.insert("Blah");
MyContainer<int> intContainer;
intContainer.insert(3342);
You can take a look at boost::any class. It is type safe, you can put it into standard collections and you don't need to link with any library, the class is implemented in header file.
It allows you to write code like this:
#include <list>
#include <boost/any.hpp>
typedef std::list<boost::any> collection_type;
void foo()
{
collection_type coll;
coll.push_back(boost::any(10));
coll.push_back(boost::any("test"));
coll.push_back(boost::any(1.1));
}
Full documentation is here: http://www.boost.org/doc/libs/1_40_0/doc/html/any.html
What you are looking for are templates. They allow you to make classes and function which allow you to take any datatype whatsoever.
Templates are the static way to do this. They behave like Java and C# generics but are 100% static (compile time). If you d'ont need to store different types of objetcs in the same container, use this (other answers describe this very well).
However, if you need to store different types of objects in the same container, you can do it the dynamic way, by storing pointers on a base class. Of course, you have to define your own objects hierarchy, since there is no such "Object" class in C++ :
#include <list>
class Animal {
public:
virtual ~Animal() {}
};
class Dog : public Animal {
public:
virtual ~Dog() {}
};
class Cat : public Animal {
public:
virtual ~Cat() {}
};
int main() {
std::list<Animal*> l;
l.push_back(new Dog);
l.push_back(new Cat);
for (std::list<Animal*>::iterator i = l.begin(); i!= l.end(); ++i)
delete *i;
l.clear();
return 0;
}
A smart pointer is easier to use. Example with boost::smart_ptr:
std::list< boost::smart_ptr<Animal> > List;
List.push_back(boost::smart_ptr<Animal>(new Dog));
List.push_back(boost::smart_ptr<Animal>(new Cat));
List.clear(); // automatically call delete on each stored pointer
You should be able to cast a void* into a string* using standard C-style casts. Remember that a reference is not treated like a pointer when used, it's treated like a normal object. So if you're passing a value by reference to a function, you still have to de-refrence it to get its address.
However, as others have said, a better way to do this is with templates
static_cast<char*>(str.c_str())
looks odd to me. str.c_str() retrieves the C-like string, but with type const char *, and to convert to char * you'd normally use const_cast<char *>(str.c_str()). Except that that's not good to do, since you'd be meddling with the internals of a string. Are you sure you didn't get a warning on that?
You should be able to use static_cast<void *>(&str). The error message you got suggests to me that you got something else wrong, so if you could post the code we could look at it. (The data type std::string& is a reference to a string, not a pointer to one, so the error message is correct. What I don't know is how you got a reference instead of a pointer.)
And, yes, this is verbose. It's intended to be. Casting is usually considered a bad smell in a C++ program, and Stroustrup wanted casts to be easy to find. As has been discussed in other answers, the right way to build a data structure of arbitrary base type is by using templates, not casts and pointers.