My apologies in advance, but I can't find this one.
In C++ I want a have a map. This map will consist of <string, Object>; where the objects are added dynamical from an XML document during runtime. The Object will either be a int, double, string, or array of ints, doubles, or string. The key is guaranteed to be unique. However, I need a way to dynamically declare this using a map.
Is this perhaps an instance when I should be using a template for the data part?
I can't use a large lib such as boost to achieve this, since this should be a light wight program.
(Ref: Use boost C++ libraries?)
This is similar to what im trying to achieve. Where the user specified the primitive type: (Ref: Creating dictionary that map type T as key to instance of type T)
std::map <std::string, ????> Values;
Edit:
So if I can't use boost, could I achieve this using a template?
In boost I am dong this:
typedef boost::variant<int, double, std::string> datum;
std::map<std::string, datum> Parms;
Then I later adding values during run-time (from XML, where each element has an attribute with the specified type)
Parms["a"] = 10; // int
Parms["b"] = 102.2039; // double
Parms["c"] = 6.6667e-07; // another double
Parms["d"] = "Hello world"; // std::string
The problem is when I do this:
datum v1 = obj.get("c"); // need double, not datum
You could consider embedding your primitive type in a struct. You can define a base class from which the different structs are derived. You probably need to save the type as well into the struct, but I left it out for simplicity.
If you really need the primitive types, ignore my answer and go for Boost.
#include <map>
#include <string>
struct BaseObject {};
struct ObjectInt : public BaseObject
{
int a;
};
struct ObjectString : public BaseObject
{
std::string a;
};
int main()
{
BaseObject *oi, *os;
oi = new ObjectInt;
os = new ObjectString;
std::map<std::string, BaseObject *> objectMap;
objectMap["oi"] = oi;
objectMap["os"] = os;
delete oi;
delete os;
return 0;
}
Related
Guys I have a function like this (this is given and should not be modified).
void readData(int &ID, void*&data, bool &mybool) {
if(mybool)
{
std::string a = "bla";
std::string* ptrToString = &a;
data = ptrToString;
}
else
{
int b = 9;
int* ptrToint = &b;
data = ptrToint;
}
}
So I want to use this function in a loop and save the returned function parameters in a vector (for each iteration).
To do so, I wrote the following struct:
template<typename T>
struct dataStruct {
int id;
T** data; //I first has void** data, but would not be better to
// have the type? instead of converting myData back
// to void* ?
bool mybool;
};
my main.cpp then look like this:
int main()
{
void* myData = nullptr;
std::vector<dataStruct> vec; // this line also doesn't compile. it need the typename
bool bb = false;
for(int id = 1 ; id < 5; id++) {
if (id%2) { bb = true; }
readData(id, myData, bb); //after this line myData point to a string
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
}
}
Or is there a better way to do that without template? I used c++11 (I can't use c++14)
The function that you say cannot be modified, i.e. readData() is the one that should alert you!
It causes Undefined Behavior, since the pointers are set to local variables, which means that when the function terminates, then these pointers will be dangling pointers.
Let us leave aside the shenanigans of the readData function for now under the assumption that it was just for the sake of the example (and does not produce UB in your real use case).
You cannot directly store values with different (static) types in a std::vector. Notably, dataStruct<int> and dataStruct<std::string> are completely unrelated types, you cannot store them in the same vector as-is.
Your problem boils down to "I have data that is given to me in a type-unsafe manner and want to eventually get type-safe access to it". The solution to this is to create a data structure that your type-unsafe data is parsed into. For example, it seems that you inteded for your example data to have structure in the sense that there are pairs of int and std::string (note that your id%2 is not doing that because the else is missing and the bool is never set to false again, but I guess you wanted it to alternate).
So let's turn that bunch of void* into structured data:
std::pair<int, std::string> readPair(int pairIndex)
{
void* ptr;
std::pair<int, std::string> ret;
// Copying data here.
readData(2 * pairIndex + 1, ptr, false);
ret.first = *reinterpret_cast<int*>(ptr);
readData(2 * pairIndex + 2, ptr, true);
ret.second = *reinterpret_cast<std::string*>(ptr);
}
void main()
{
std::vector<std::pair<int, std::string>> parsedData;
parsedData.push_back(readPair(0));
parsedData.push_back(readPair(1));
}
Demo
(I removed the references from the readData() signature for brevity - you get the same effect by storing the temporary expressions in variables.)
Generally speaking: Whatever relation between id and the expected data type is should just be turned into the data structure - otherwise you can only reason about the type of your data entries when you know both the current ID and this relation, which is exactly something you should encapsulate in a data structure.
Your readData isn't a useful function. Any attempt at using what it produces gives undefined behavior.
Yes, it's possible to do roughly what you're asking for without a template. To do it meaningfully, you have a couple of choices. The "old school" way would be to store the data in a tagged union:
struct tagged_data {
enum { T_INT, T_STR } tag;
union {
int x;
char *y;
} data;
};
This lets you store either a string or an int, and you set the tag to tell you which one a particular tagged_data item contains. Then (crucially) when you store a string into it, you dynamically allocate the data it points at, so it will remain valid until you explicitly free the data.
Unfortunately, (at least if memory serves) C++11 doesn't support storing non-POD types in a union, so if you went this route, you'd have to use a char * as above, not an actual std::string.
One way to remove (most of) those limitations is to use an inheritance-based model:
class Data {
public:
virtual ~Data() { }
};
class StringData : public Data {
std::string content;
public:
StringData(std::string const &init) : content(init) {}
};
class IntData : public Data {
int content;
public:
IntData(std::string const &init) : content(init) {}
};
This is somewhat incomplete, but I think probably enough to give the general idea--you'd have an array (or vector) of pointers to the base class. To insert data, you'd create a StringData or IntData object (allocating it dynamically) and then store its address into the collection of Data *. When you need to get one back, you use dynamic_cast (among other things) to figure out which one it started as, and get back to that type safely. All somewhat ugly, but it does work.
Even with C++11, you can use a template-based solution. For example, Boost::variant, can do this job quite nicely. This will provide an overloaded constructor and value semantics, so you could do something like:
boost::variant<int, std::string> some_object("input string");
In other words, it's pretty what you'd get if you spent the time and effort necessary to finish the inheritance-based code outlined above--except that it's dramatically cleaner, since it gets rid of the requirement to store a pointer to the base class, use dynamic_cast to retrieve an object of the correct type, and so on. In short, it's the right solution to the problem (until/unless you can upgrade to a newer compiler, and use std::variant instead).
Apart from the problem in given code described in comments/replies.
I am trying to answer your question
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
Before that you need to modify vec definition as following
vector<dataStruct<void>> vec;
Now you can simple push element in vector
vec.push_back({id, &mydata, bb});
i have tried to modify your code so that it can work
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct dataStruct
{
int id;
T** data;
bool mybool;
};
void readData(int &ID, void*& data, bool& mybool)
{
if (mybool)
{
data = new string("bla");
}
else
{
int b = 0;
data = &b;
}
}
int main ()
{
void* mydata = nullptr;
vector<dataStruct<void>> vec;
bool bb = false;
for (int id = 0; id < 5; id++)
{
if (id%2) bb = true;
readData(id, mydata, bb);
vec.push_back({id, &mydata, bb});
}
}
Can anyone guide me on how to solve this problem.
I have a boost::variant.
typedef boost::variant <
int,
std::string,
bool,
double,
vector<int>,
vector<string>,
vector<bool>,
vector<double>
> boostVar;
I am trying to create overload [] operator as member function of a class ABC something like this (this is just a dummy implementation)
class ABC
{
//some map of (key, value) pair that where key is string and value is of type boostVar
boostVar [](const string key)
{
boostVar temp;
//some operation that fills up temp based on value of key
return temp;
}
}
So while retrieving the a particular value using this implementation, it forces user to specify
int key1Val = boost::get<int>(ABC["KEY1"]);
bool key2Val = boost::get<bool>(ABC["KEY2"]);
vector<int> key3Val = boost::get<vector<int>>(ABC["KEY3"]);
my question is:
How should I go about implementing this if I want to access the values like below (i.e. without boost::get<>)
int key1Val = ABC["KEY1"];
bool key2Val = ABC["KEY2"];
vector<int> key3Val = ABC["KEY3"];
The implementation should give warning to user if the say: KEY1 does not match int, KEY2 does not match bool and so on.
You'd need to use a class to wrap the boost variant and add the conversion behaviours. At it's simplest - in the common case where realistically client code won't be trying to delete dynamically allocated instances using pointers to the base (boost::variant<...>*) - it could look something like this:
struct Variant : boost::variant<int, std::string, ...etc...>
{
operator int() const { return boost::get<int>(*this); }
operator std::string() const { return boost::get<std::string>(*this); }
...etc...
};
This will provide the same checks get<> provides: compile time checks that you're trying to assign to one of the types the variant could hold at runtime, and runtime checks that it does actually hold the exact destination type when you try to assign from it.
If you can't be sure client code won't delete via the base class pointer, consider private inheritance or composition (you will need to do more work to expose any other variant functionality your client code may want to access).
(ABC::operator[](const std::string& key) const can just return such a Variant).
I am currently implementing a data storage for a large table in C++. The table needs to be able to store different data type for each of a variable number of columns.
The type and the length of each column are defined and run-time. Because of this, I figured, a vector of pointer to vectors would be the right approach. I can however not figure out how to do this with variable data types.
I looked at How to get a vector of different vectors in C++ but there is not dynamic solution.
I am open to any other solutions, I don't necessarily need vectors, but the table should be re-sizable at run-time.
It should look something like this:
0 1 2 3 ...
- - - - -
1 a 0 1.3 ...
2 b 1 2.5 ...
3 c 0 1.5 ...
4 d 0 0.8 ...
5 e 1 1.2 ...
.. .. .. ... ...
I some people have suggested using boost::any but I am a bit reluctant of this (in terms of efficiency) because the table has to load large packet files from disk.
The any Class implemented in boost will do what you need.
Here is an example how to use it from their website:
#include <vector>
#include <boost/any.hpp>
using boost::any_cast;
typedef std::vector<boost::any> many;
void append_int(many & values, int value)
{
boost::any to_append = value;
values.push_back(to_append);
}
void append_string(many & values, const std::string & value)
{
values.push_back(value);
}
void append_char_ptr(many & values, const char * value)
{
values.push_back(value);
}
void append_any(many & values, const boost::any & value)
{
values.push_back(value);
}
void append_nothing(many & values)
{
values.push_back(boost::any());
}
If you cannot use boost and do not want to re-implement boost::any you could use void * as the poor man's any container. The table level would be a std::vector<void *> and each column (of type T) would be a std::vector<T>. You then allocate each column in turn and store the address of the column in the initial std::vector<void *>.
Provided you cast the value of each column before using it it should work. Depending on your requirements it may be more or less simple to implement that correctly because as you have raw pointers you should implement carefully the destructors and if appropriate copy an move constructors and assignements or declare them deleted. But it is a (poor man's) boost alternative...
To store different types in vector is impossible, but if you store pointers without type (void*), then you can retype it to any type you want. If you don't know at runtime what type you are reading, then make struct containing pointer void* and variable to determine type.
It's while since I used C++ so example can be just pseudo C++.
#include<vector>
#include<iostream>
void workWithCharArray(char* c);
typedef struct mytype {
int type = 0; // this defining default values is available since C++11
void* var = nullptr;
} Mytype;
int main() {
char* ptr = (char*)"Testing string";
std::vector<Mytype> container;
Mytype tostore;
tostore.type = 1;
tostore.var = (void*)ptr;
container.append(tostore);
switch (tostore.type) {
case 1:
workWithCharArray((char*)tostore.var);
break;
default:
std::cerr << "Unknown type - Error handling";
}
return 0;
}
void workWithCharArray(char* c) {
std::cout << c << std::endl;
}
If you need a two-dimensional vector that stores one-dimensional vectors of different data types, you could create an abstract, non-templated base class for the inner vector and then store pointers to that abstract base class in the outer vector, utilising polymorphism if you want to call member functions on the abstract vectors.
class AbstractVector {
... // provide pure virtual interface here
}
template<class T>
class MyVector : public AbstractVector, public std::vector<T> {
... /* provide implementation of pure virtual interface using
already available functionality from std::vector here */
}
In your implementation you can then store pointers to the base class AbstractVector (or unique_ptrs or shared_ptrs depending on what you want to do):
std::vector<AbstractVector *> table;
MyVector<int> * columnOne = new MyVector<int>;
MyVector<float> * columnTwo = new MyVector<float>;
table.push_back(columnOne);
table.push_back(columnTwo);
This seems like it may be impossible, but I thought I would ask anyway.
I have defined a boost::variant like this:
typedef boost::variant<double, int, std::string> ConfigVariant;
Later in my code I define a std::map like this:
std::map<std::string, ConfigVariant> my_map;
Now I would like to be able to have std::map<std::string, ConfigVariant> values inside my_map. For example, I would like to do this:
my_map[key1][key2] = "hello world";
The reason I think this is impossible is because it seems like the corresponding variant definition would look like this:
typedef boost::variant<double, int, std::string, std::map<std::string, ConfigVariant> ConfigVariant;
Since making such a type definition would be impossible, is there any way around this?
The official documentation has a section on recursive variant types. It explains two approaches: using boost::recursive_wrapper and boost::make_recursive_variant. I'm not sure that it is possible to define this kind of recursion with recursive_wrapper (I have never been able to personally, but I'm far from an expert). In contrast with make_recursive_variant it is really easy: you just need to replace your recursive variant type with boost::recursive_variant_ and then use ::type to evaluate the metafunction and get the type you want.
typedef boost::make_recursive_variant<
double,
int,
std::string,
//std::map<std::string,ConfigVariant>
std::map<std::string,boost::recursive_variant_>
>::type ConfigVariant;
Running on coliru
#include <iostream>
#include <string>
#include <map>
#include <boost/variant.hpp>
typedef boost::make_recursive_variant<double, int, std::string, std::map<std::string, boost::recursive_variant_> >::type ConfigVariant;
struct printer : boost::static_visitor<>
{
void operator()(int val) const
{
std::cout << val;
}
void operator()(double val) const
{
std::cout << val;
}
void operator()(const std::string& val) const
{
std::cout << val;
}
void operator()(const std::map<std::string,ConfigVariant>& val) const
{
std::cout << "map_of{ ";
for(std::map<std::string,ConfigVariant>::const_iterator it=val.begin(),end=val.end(); it!=end; ++it)
{
boost::apply_visitor(*this,it->second);
std::cout << " ";
}
std::cout << "}";
}
};
int main()
{
ConfigVariant intconf=1;
ConfigVariant doubleconf=1.2;
ConfigVariant stringconf="conf";
std::map<std::string, ConfigVariant> mapconf, mapconf2;
mapconf["int"]=intconf;
mapconf["string"]=stringconf;
mapconf2["map"]=mapconf;
mapconf2["double2"]=doubleconf;
ConfigVariant visitable=mapconf2;
boost::apply_visitor(printer(), visitable);
std::cout << std::endl;
}
The question doesn't really have anything to do with boost::variant; you are simply asking to make an n-ary tree using a standard container.
The answer is no, because the standard containers require complete types to be used as their template arguments. A container cannot contain itself because, as you observed, the definition would be recursive. Its constructor would presuppose that its constructor already existed. The result would be an incomplete type error.
As a special case, in fact std::vector implementations often do allow this to be done. The constructor (and anything else requiring a complete element type) is not actually instantiated until the class definition of vector is complete. And all the standard containers could be implemented to make it work in the same way. But it's not required by the Standard.
See also Can standard container templates be instantiated with incomplete types? ; this also contains a workaround. To make the workaround apply to variant, which requires a complete type by itself, I'd suggest wrapping the incomplete type in std::unique_ptr.
It sounds like you want:
typedef boost::variant<double, int, std::string> ConfigVariant;
std::map<std::string, std::map<std::string, ConfigVariant> > my_map;
This would enable access of the form:
my_map["key 1"]["key 2"] = "hello world";
But not of the form:
my_map["key 1"] = "hello world";
Using boost::any would make that work for you.
I also just a half-hour ago wrote this code, which would also work in your situation in place of boost::variant.
It's basically just a glorified void* pointer, but with type-checking asserts. I'd guess boost::any is also just a void* under the hood, but I'm not sure.
I forgot my code doesn't take ownership of the data (by intention) - you'll have to modify so it does if you wanted to use it. That might prove difficult. boost::any takes ownership, so that might be the better option.
Your code would then be:
typedef std::map<std::string, boost::any> ConfigMap;
Or using smart pointers:
struct Data;
typedef std::map<std::string, std::unique_ptr<Data> > ConfigMap;
struct Data
{
boost::variant<blah> value;
ConfigMap map;
};
Think of it like a folder structure. Folders contain files, and they can also contain folders.
Here's it compiling at Ideone.com. It'd be nicer wrapped in a user-friendly class though.
I have some data class which is expensive to copy, but must be mutable, as it is frequently updated according to events. I also need a multi-index container to hold many such classes. I'm trying to set it up using boost::multi_index. For example:
struct MutableAndExpensiveToCopy {
int some_value;
std::map<int, std::string> some_huge_map;
std::map<int, std::string> an_even_bigger_map;
}
struct CanBeMultiIndexed
{
// "Payload" - its fields will never be used as indices
MutableAndExpensiveToCopy data;
// Indexes
int id;
std::string label;
}
typedef multi_index_container<
CanBeMultiIndexed,
indexed_by<
ordered_unique<member<CanBeMultiIndexed, int, &CanBeMultiIndexed::id>>,
ordered_non_unique<member<CanBeMultiIndexed,std::string,&CanBeMultiIndexed::label>>
>
> MyDataContainer;
My problem is that multi_index treats elements in the container as constants (in order to keep the integrity of all of the indices). For example, the following won't compile:
void main() {
// put some data in the container
MyDataContainer container;
CanBeMultiIndexed e1(1, "one"); // conto'r not shown in class definition for brevity
CanBeMultiIndexed e2(2, "two");
container.insert(e1);
container.insert(e2);
// try to modify data
MyDataContainer::nth_index<1>::type::iterator iter = container.get<1>().find(1);
iter->data.some_value = 5; // constness violation
}
I cannot use the replace() method, as it is expensive to copy the payload class.
I'm aware of the modify() method, but using it seems cumbersome, since in my real program, the "payload" class may contain numerous fields, and writing a functor for each and every one it out of the question.
Any suggestions?
EDIT: After some playing around, I've tried replacing the data element with a shared_ptr to MutableAndExpensiveToCopy:
struct CanBeMultiIndexed
{
// "Payload" - its fields will never be used as indices
boost::shared_ptr<MutableAndExpensiveToCopy> data;
// Indexes
int id;
std::string label;
}
This worked, and I was able to compile my main() including the data-modifying code:
void main() {
...
iter->data->some_value = 5; // this works
...
}
This pretty much gives me what I wanted, but I'm not sure why this works, so:
Does this code does what I intended, or is there some caveat I'm missing?
How come this works? Does the constness of the shared_ptr does not apply to its -> operator?
First of all, ImMutableAndExpensiveToCopy seems precisely to be the opposite --mutable, since you're trying to change its contents in the example. Try simply this:
struct CanBeMultiIndexed
{
mutable ImMutableAndExpensiveToCopy data;
int id;
std::string label;
}
(and possibly change the name ImMutableAndExpensiveToCopy for consistency.)