Is there a simple way to understand which union member is active?
An example:
union Read_Value{
char ch;
float number;
string str;
}
Suppose a void function reads from an input file stream and initialise Read_Value on the base of the type of the variable read. Assuming I don't know how the function works, how can I understand which of the three member is active?
A bare union cannot tell you which is the active element. You have to keep track of that yourself.
Since C++17 std::variant is the "modern union". It has a index() method that tells you which is the active index. Example from cppreference:
#include <variant>
#include <string>
#include <iostream>
int main()
{
std::variant<int, std::string> v = "abc";
std::cout << "v.index = " << v.index() << '\n';
v = {};
std::cout << "v.index = " << v.index() << '\n';
}
Possible output:
v.index = 1
v.index = 0
Is there a simple way to understand which union member is active?
In general, using a tagged (or discriminated) union. This means storing some metadata (tracking which member is active) alongside the raw union.
The modern solution is indeed std::variant, which does all this for you.
If you don't have C++17 support, don't have it in your standard library's experimental or tr extensions, and for some reason can't use the Boost.variant precursor ... you can still write an old-style tagged union yourself.
I wouldn't call it simple though, at least not to do well.
If I have a std::any of an std::string or an int, how could I cast this into the type that's contained?
std::any has type on it, however I can't use this type to cast.
Example:
#include <any>
#include <iostream>
#include <string>
int main(void) {
std::any test = "things";
std::any test2 = 123;
// These don't work
std::string the_value = (std::string) test;
int the_value2 = (int) test2;
std::cout << the_value << std::endl;
std::cout << the_value2 << std::endl;
}
You use any_cast to do the trick. For example
auto a = std::any(12);
std::cout << std::any_cast<int>(a) << '\n';
You can find more details from cppreference
If you want to dynamically cast the value inside a std::any, you can try
if (a.type() == typeid(int)) {
cout << std::any_cast<int>(a) << endl;
} else if (a.type() == typeid(float)) {
cout << std::any_cast<float>(a) << endl;
}
If you do not have a list of types among which the any holds one, you cannot convert the any to its type and operate on it as its real type.
You can store a type in an any, and an operation in that type as a function pointer on that any. But this must be done at the moment of storage or when you do have a list (possibly with 1 element) of the possible types stored in the any.
C++ does not store sufficient information within an any to permit arbitrary code to be compiled on that type when it stores the value in the any. C++ does not permit full "reification" at runtime.
Type erasing type erasure, `any` questions? Q&A by a stackoverflow user of ill repute gives an example of how to remember some operation on the contents of the any while still forgetting the type stored.
If you do have such a list of possible types, consider using variant. any exists in the narrow window where you do not know the types stored at container design time, but do at both insert and removal.
In that narrow window, you can do runtime tests based off the typeid stored and cast to the known type using any_cast.
I've been given the task to refactor a bunch of C++ code that has a lot of math and not an explanation of what it does.
In order to do that I've setup a bunch of automated test that given random data compare old and new code results.
The thing is that, while it is simple to generate random vector of any size I have a lot of "struct" with many public fields (> 20) I'm a bit tired of writing custom function to fill them.
One can think of using some kind of script to parse the definition and autobuild the corresponding generator function.
Do you think this is a good idea ?
Is there anything like that already done?
If you have only Plain Old Data, a struct is, roughly, merely a blob of memory with some meaning to the compiler.
This means you can treat it as such, and simply fill it with random bytes, using a union:
struct a {
int i;
char c;
float f;
double d;
};
union u {
char arr[sizeof(a)];
a record;
};
char generateRandomChar(); // implement some random char generation
int main() {
u foo;
for (char& c : foo.arr) {
c = generateRandomChar();
}
std::cout << "i:" << foo.record.i
<< "\nc:" << foo.record.c
<< "\nf:" << foo.record.f
<< "\nd:" << foo.record.d;
}
See it live!
Technically, this is Undefined Behavior. In practice, it is well defined in most compilers.
Let's assume that A and B are two classes (or structures) having no inheritance relationships (thus, object slicing cannot work). I also have an object b of the type B. I would like to interpret its binary value as a value of type A:
A a = b;
I could use reinterpret_cast, but I would need to use pointers:
A a = reinterpret_cast<A>(b); // error: invalid cast
A a = *reinterpret_cast<A *>(&b); // correct [EDIT: see *footnote]
Is there a more compact way (without pointers) that does the same? (Including the case where sizeof(A) != sizeof(B))
Example of code that works using pointers: [EDIT: see *footnote]
#include <iostream>
using namespace std;
struct C {
int i;
string s;
};
struct S {
unsigned char data[sizeof(C)];
};
int main() {
C c;
c.i = 4;
c.s = "this is a string";
S s = *reinterpret_cast<S *>(&c);
C s1 = *reinterpret_cast<C *>(&s);
cout << s1.i << " " << s1.s << endl;
cout << reinterpret_cast<C *>(&s)->i << endl;
return 0;
}
*footnote: It worked when I tried it, but it is actually an undefined behavior (which means that it may work or not) - see comments below
No. I think there's nothing in the C++ syntax that allows you to implicitly ignore types. First, that's against the notion of static typing. Second, C++ lacks standardization at binary level. So, whatever you do to trick the compiler about the types you're using might be specific to a compiler implementation.
That being said, if you really wanna do it, you should check how your compiler's data alignment/padding works (i.e.: struct padding in c++) and if there's a way to control it (i.e.: What is the meaning of "__attribute__((packed, aligned(4))) "). If you're planning to do this across compilers (i.e.: with data transmitted across the network), then you should be extra careful. There are also platform issues, like different addressing models and endianness.
Yes, you can do it without a pointer:
A a = reinterpret_cast<A &>(b); // note the '&'
Note that this may be undefined behaviour. Check out the exact conditions at http://en.cppreference.com/w/cpp/language/reinterpret_cast
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 that whenever I try to populate, say, a map, vector or list with, say, the following:
int x;
string y;
double z;
I'm restricted with the format:
list<int> mycountainer;
vector<string> mycontainer;
which forces mycontainer to only consist of one type.
Before anyone suggest generics, that wouldn't work either since the standard vector and list containers that come with C++ are already generic - they can be container for any types but cannot contain multiple types.
I would like to avoid using Boost also if at all possible - I'd prefer it if there is a simple way I could code this myself.
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.
Well, the first question would be: Why do you think you need to store objects of different, totally unrelated types in the same container? That seems fishy to me.
If I had the need, I'd look into boost::variant or boost::any.
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 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)));
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.
What I have for this question is not what I hoped would work. By what I think that you would like, is a container that stores multiple value types, that you can access at will.
However, as such, a container would have to specify what value it holds, so you could have a class with 500 data types in it, with a correlating constructor for each data type, however, that would be super memory inefficient.
Here is my proposed suggestion, I have worked on for a day, And I hope it meets your criteria:
#include <iostream>
#include <vector>
using namespace std;
enum class type: unsigned int {int_t, unsigned_int_t, string_t, double_t, float_t, bool_t, unipointer_t, vector_int_t, vector_unipointer_t};//just add item types here and in the switch statement to hold more void_ps in unipointer...
class unipointer {
void* obj;//the pointer to the data. any type of pointer.
type objtype;//the object type, kept as an enum class.
struct void_p {//template magic... ;D
void* void_ptr;
template<typename T>//when object is initialized, it converts the the void* pointer to the output value.
operator T() {
return reinterpret_cast<T&>(void_ptr);
}
void_p(void* val): void_ptr(val) {};
};
public:
unipointer(void_p ptr, type ptrtype) : obj(ptr), objtype(ptrtype) {}
type get_type(void) {//Once you call this function, you know the type of data stored, and can call other functions accordingly.
return objtype;
}
template<typename T>//With a temlate, get any value through a pointer to it.
T get_ptr(void){
return reinterpret_cast<T&>(obj);
}
template<typename T>//With a temlate, get any value, as an object
T get_object(void) {
return *get_ptr<T*>();
}
void_p get_auto_pointer(void) {//get any pointer to value, can't be assigned to "auto*"!
return unipointer::void_p(obj);
}
void_p get_auto_object(void) {//get any value, can't be assigned to "auto"!
return *(void_p*)get_auto_pointer();
}
};
void process_stuff(unipointer& thing, unsigned int num_of_tabs);
int main() {
double initialization = 1.2345;
float even_another = 3.14159f;
unipointer items(new vector<unipointer>{//one thicc object instance
//Initialization examles:
unipointer(new int(-12345), type::int_t),
unipointer(new unsigned int(4'294'967'295), type::unsigned_int_t),
unipointer(new string("That is how I store my items."), type::string_t),
unipointer(&initialization, type::double_t),
unipointer(&even_another, type::float_t),
unipointer(new bool(1), type::bool_t),
unipointer(new unipointer(new unipointer(new unipointer(new string("OMG! NESTING!"), type::string_t), type::unipointer_t), type::unipointer_t), type::unipointer_t),
unipointer(new vector<int>{ 1,2,3 }, type::vector_int_t),
unipointer(new vector<unipointer>{
unipointer(new string("That is how I store my nested items."), type::string_t),
unipointer(new vector<int>{4,5,6}, type::vector_int_t),
unipointer(new string("Is your head brimming with ideas yet?"), type::string_t)
} , type::vector_unipointer_t)
}, type::vector_unipointer_t);
cout << "What is in the \"items\" unipointer:" << endl;
process_stuff(items, 1);
system("pause");
}
void process_stuff(unipointer& thing, unsigned int num_of_tabs) {
//declare variables & lamda for interpretaion methods, using variable assignment with "get auto object/pointer"
unsigned int* test = 0;
double test_2 = 0;
auto tab_to_current = [num_of_tabs]() {
for (unsigned int i = 0; i < num_of_tabs; ++i) {
cout << "\t";
}
};
//format the thing.
tab_to_current();
//look through and do stuff
switch (thing.get_type()) {//just add item types here and in the enum class to hold more void_ps in unipointer...
case type::int_t:
cout << "The integer: " << *thing.get_ptr<int*>() << "." << endl;//one way of getting object back from class
break;
case type::string_t:
cout << "The string: \"" << thing.get_object<string>() << "\"." << endl;//another way
break;
case type::unsigned_int_t:
test = thing.get_auto_pointer();//another way
cout << "The unsigned integer: " << *test << "." << endl;//don't forget to de-reference it!
delete test;
break;
case type::double_t:
test_2 = thing.get_auto_object();
cout << "The double: " << test_2 << "." << endl;//even another way!
break;
case type::float_t:
cout << "The float: " << float(thing.get_auto_object()) << "." << endl;//even another way!
break;
case type::bool_t:
cout << "The boolean: " << *(bool*)thing.get_auto_pointer() << "." << endl;//even another way!
break;
case type::unipointer_t:
cout << "A unipointer, and in it:" << endl;
process_stuff(*&thing.get_object<unipointer>(), num_of_tabs+1);
tab_to_current();
cout << "[End of unipointer]" << endl;
break;
case type::vector_int_t:
cout << "A vector of integers, and in it:" << endl;
for (unsigned int i = 0; i < thing.get_object<vector<int>>().size(); ++i) {
tab_to_current();
cout << "\tItem " << i << ": " << thing.get_object<vector<int>>().at(i) << endl;
}
tab_to_current();
cout << "[End of vector of integers]" << endl;
break;
case type::vector_unipointer_t:
cout << "A vector of unipointers, and in it:" << endl;
for (unsigned int i = 0; i < thing.get_object<vector<unipointer>>().size(); ++i) {
process_stuff(*&thing.get_object<vector<unipointer>>().at(i), num_of_tabs + 1);
}
tab_to_current();
cout << "[End of unipointer vector]" << endl;
break;
}
}
The "unipointer" class should be initialized with a pointer to any object type, and also the type of object. The class can return, through a function, your data, although it is not very safe, and could be called with the wrong type of data.
This is just an example of what could work, I sure hope that you take inspiration from it.
And, to answer your original question, you would set up a list, or vector with the following format:
vector/list:
|
|unipointer(*double)
|
|unipointer(*int)
|
|unipointer(*string)
|
...
|
end
PS: I am a beginner with objects and templates, so this might be messy. Many apoligies.
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.