Registry of different types of data - c++

I want to keep some kind of container where a type maps to one value of the type. So essentially what I want is a std::map<std::typeindex, T> where T depends on the type I index it with. std::map doesn't look like a nice way of doing this because the types are rigid. What is the simplest solution I can use for doing this?

If you map to a type-erased container like boost::any, you can at least recover the type if you know what it is:
std::map<std::typeindex, boost::any> m;
m[typeid(Foo)] = Foo(1, true, 'x');
Foo & x = boost::any_cast<Foo&>(m[typeid(Foo)]);

You could use a shared_ptr<void>:
std::map<std::typeindex, std::shared_ptr<void>> m;
m[typeid(T)] = std::make_shared<T>(...);
auto pT = std::static_pointer_cast<T>(m[typeid(T)]); // pT is std::shared_ptr<T>
Or course you would add some wrapper to ensure that the two Ts per line match and you don't accidentially access an empty shared_ptr<void>.

Related

c++: variadic nested maps aka dictionary

I'd like to have a container in cpp that kind of behaves like python dictionaries do, at least in the following regards:
key-value structure (key might be restricted to a single type)
variadic value type (might be restricted to some pod types[int, double, string])
deeply nested (arbitrary depth, but not necessary dynamic)
randomly accessed
accessed type is stored type
So at best, the following example should work;
typedef DictionaryContainer<string, <int, string, bool>, 2> Dict;
Dict mydict; //key-type is string, value-type one of int, string or bool, nested to depth 2
mydict["a"] = 1;
mydict["b"] = true;
mydict["c"] = 'string';
mydict["d"] = Dict();
mydict["d"]["a"] = false;
std::any& dict_d_a = mydict["d"]["a"]; // stores a bool
std::string& dict_c = mydict["c"]; // possibly get<std::string>(mydict["c"])
Is there anything like this out there? I have found containers that allow storing arbitrary types, like boost::variant but they do not allow random access and recursively defined containers (as far as I have figured it out).
Is there not some implementation of a tree / map that can be used in such way?

How to implement something like std::copy_if but apply a function before inserting into a different container

Full disclosure, this may be a hammer and nail situation trying to use STL algorithms when none are needed. I have seen a reappearing pattern in some C++14 code I am working with. We have a container that we iterate through, and if the current element matches some condition, then we copy one of the elements fields to another container.
The pattern is something like:
for (auto it = std::begin(foo); it!=std::end(foo); ++it){
auto x = it->Some_member;
// Note, the check usually uses the field would add to the new container.
if(f(x) && g(x)){
bar.emplace_back(x);
}
}
The idea is almost an accumulate where the function being applied does not always return a value. I can only think of a solutions that either
Require a function for accessing the member your want to accumulate and another function for checking the condition. i.e How to combine std::copy_if and std::transform?
Are worse then the thing I want to replace.
Is this even a good idea?
A quite general solution to your issue would be the following (working example):
#include <iostream>
#include <vector>
using namespace std;
template<typename It, typename MemberType, typename Cond, typename Do>
void process_filtered(It begin, It end, MemberType iterator_traits<It>::value_type::*ptr, Cond condition, Do process)
{
for(It it = begin; it != end; ++it)
{
if(condition((*it).*ptr))
{
process((*it).*ptr);
}
}
}
struct Data
{
int x;
int y;
};
int main()
{
// thanks to iterator_traits, vector could also be an array;
// kudos to #Yakk-AdamNevraumont
vector<Data> lines{{1,2},{4,3},{5,6}};
// filter even numbers from Data::x and output them
process_filtered(std::begin(lines), std::end(lines), &Data::x, [](int n){return n % 2 == 0;}, [](int n){cout << n;});
// output is 4, the only x value that is even
return 0;
}
It does not use STL, that is right, but you merely pass an iterator pair, the member to lookup and two lambdas/functions to it that will first filter and second use the filtered output, respectively.
I like your general solutions but here you do not need to have a lambda that extracts the corresponding attribute.
Clearly, the code can be refined to work with const_iterator but for a general idea, I think, it should be helpful. You could also extend it to have a member function that returns a member attribute instead of a direct member attribute pointer, if you'd like to use this method for encapsulated classes.
Sure. There are a bunch of approaches.
Find a library with transform_if, like boost.
Find a library with transform_range, which takes a transformation and range or container and returns a range with the value transformed. Compose this with copy_if.
Find a library with filter_range like the above. Now, use std::transform with your filtered range.
Find one with both, and compose filtering and transforming in the appropriate order. Now your problem is just copying (std::copy or whatever).
Write your own back-inserter wrapper that transforms while inserting. Use that with std::copy_if.
Write your own range adapters, like 2 3 and/or 4.
Write transform_if.

Insert into container of container if new or append to existing

I have a container that looks like this:
std::map<std::string, std::vector<double>> id_values;
I will iterate through other pairs of doubles and strings, and I want to add a new element to the map if it doesn't exist, or append to the vector if it does. Is there a more succinct solution than the following?
auto loc = id_values.find(key);
if (loc != id_values.end()) {
loc->second.push_back(val);
} else {
loc.insert({key, {val}});
}
I suppose I could do a ternary operator but I feel that will make the code less readable, I'm more wondering if there is a better pattern for what I'm trying to achieve rather than conditional.
You can just use operator[]. It will return a reference to the object with the specified key if it is in the map, or if the lookup fails, it will create a new value-initialized object (an empty vector in your case) and return a reference to the new object.
id_values[key].push_back(val);
Alternatively, if you need to use different constructor arguments instead of default-constructing the mapped_type, you can use try_emplace (or regular emplace if you can't use C++17):
auto [itr, inserted] = id_values.try_emplace(key, vector_constructor_args...);
itr->second.push_back(val);
Hello I think what you want to do is ether to insert an element in your container using the method insert or the operator[].
By using the operator [] what you want to do is simply:
for(auto it: map1)
if(map2.find(it.first) == map2.end() )
map2.insert(map2.end(),it);

Shorter way to get an iterator for a std::vector

Lets say that I have got a vector like this.
std::vector<a_complicated_whatever_identifier *> *something
= new std::vector<a_complicated_whatever_identifier *>;
// by the way, is this the right way to do this?
Now I want to get an iterator for this... so I would do this like this.
std::vector<a_complicated_whatever_identifier *>::iterator iter;
But I find it a little too much for my code. I wonder, is there any more, brief way to ask for an iterator regardless of the type?
I was thinking in something like.
something::iterator iter;
// OK, don’t laugh at me, I am still beginning with C++
Well, it obviously fail, but I guess you get the idea. How to accomplish this or something similar?
You would typically give your containers sensible typedefs, and then it's a breeze:
typedef std::pair<int, Employee> EmployeeTag;
typedef std::map<Foo, EmployeeTag> SignInRecords;
for (SignInRecords::const_iterator it = clock_ins.begin(); ... )
^^^^^^^^^^^^^^^^^
Usually, having a handy typedef for the container is more practical and self-documenting that an explicit typedef for the iterator (imagine if you're changing the container).
With the new C++ (11), you can say auto it = clock_ins.cbegin() to get a const-iterator.
Use a typedef.
typedef std::vector<complicated *>::iterator complicated_iter
Then set them like this:
complicated_iter begin, end;
In C++11 you'll be able to use auto.
auto iter = my_container.begin();
In the meantime just use a typedef for the vector:
typedef std::vector<a_complicated_whatever_identifier *> my_vector;
my_vector::iterator iter = my_container.begin();
You should rarely have much need/use for defining an iterator directly. In particular, iterating through a collection should normally be done by a generic algorithm. If there's one already defined that can do the job, it's best to use it. If there's not, it's best to write your own algorithm as an algorithm. In this case, the iterator type becomes a template parameter with whatever name you prefer (usually something referring at least loosely to the iterator category):
template <class InputIterator>
void my_algorithm(InputIterator start, InputIterator stop) {
for (InputIterator p = start; p != stop; ++p)
do_something_with(*p);
}
Since they've been mentioned, I'll point out that IMO, typedef and C++11's new auto are (at least IMO) rarely a good answer to this situation. Yes, they can eliminate (or at least reduce) the verbosity in defining an object of the iterator type -- but in this case, it's basically just treating the symptom, not the disease.
As an aside, I'd also note that:
A vector of pointers is usually a mistake.
Dynamically allocating a vector is even more likely a mistake.
At least right off, it looks rather as if you're probably accustomed to something like Java, where you always have to use new to create an object. In C++, this is relatively unusual -- most of the time, you want to just define a local object so creation and destruction will be handled automatically.
// by the way, is this the right way to do this?
What you are doing is correct. The best approach depends on how you want to use that vector.
But I find it a little too much for my code. I wonder, is there any
more, brief way to ask for an iterator regardless of the type?
Yes, you can define the vector as a type:
typedef std::vector<a_complicated_whatever_identifier *> MyVector;
MyVector * vectPtr = new MyVector;
MyVector::iterator iter;
If you have a recent compiler, I suggest giving c++11 a spin. Most compilers support it in the form of the --std=c++0x flag. You can do all kinds of nifty things related to type inference:
std::list<std::map<std::string, some_complex_type> > tables;
for (auto& table: tables)
{
std::cout << table.size() << std::endl;
}
for (auto it = tables.begin(); it!= tables.end(); ++it)
{
std::cout << it->size() << std::endl;
}
Also look at decltype and many other handyness:
// full copy is easy
auto clone = tables;
// but you wanted same type, no data?
decltype(tables) empty;
Contrived example of combining typedefs with the above:
typedef decltype(tables) stables_t;
typedef stables_t::value_type::const_iterator ci_t;

Problems with map as array

Good day!
I'm making nondeterministic finite automata with c++. I want to make a transition table. As you know, it should return a set of states. For example, table[state][symbol] should return {q0,q1, etc..}.
I'm using std::map and std::set for this. I found this useful example : how to use stl::map as two dimension array
So, i wrote some code:
std::map <set<state>, std::map<state,char> > transitionTable;
But when i'm trying to acsess the table like
set<state> result = transitionTable[oldState][symbol];
I get an error:
C:\NFA2\main.cpp||In function 'std::set<state, std::less<state>, std::allocator<state> > delta(state, char)':|
C:\NFA2\main.cpp|17|error: no match for 'operator[]' in 'transitionTable[oldState]'|
Can you help me?
Thanks in advance.
From your description it sounds like you want (typedefs for readability):
typedef std::set<state> StateSet;
typedef std::map<char, StateSet> SymbolToStatesMap;
typedef std::map<state, SymbolToStatesMap> TransitionTable;
TransitionTable transitionTable;
Keep in mind that the first type argument to map is the key type, so if you want an access like this:
A a;
B b;
C c = myMap[a][b];
the map type should be:
std::map<A, std::map<B, C> >
To actually be able to use custom types as a key in a map, they have to implement operator<:
class state {
// ...
public:
bool operator<(const state& rhs) const {
// ... custom stuff here
}
Alternatively you can pass a custom comparer to map.
I assume that oldState is a set. If that is the case, transitionTable[oldState] returns you a map and transitionTable[oldState][symbol] is invalid if symbol is not a set and hence error.
std::map <set<state>, std::map<state,char> > transitionTable;
You have a set as key in the map, not a state.
What are the types of oldState and symbol?
From what I understand of your problem, I suspect that the type
of transitionTable should be:
std::map<std::set<state>, std::map<char,std::set<state> > transitionTable;
At least, this would give the mapping: (set_of_states, char) ->
set_of_states, if used as in your example, where oldState is
a set of states, and symbol is a char.