I'm Javaer for many years and a newbie in C++. Recently I need to work on a C++ project, but experience some unpleasant issues when using C++, one of them is the std:map.
I'm trying to insert a key-value pair into a map function.
map[key]=value or map.emplace(key,value) works fine, but map.insert gives me [compilation error](), which I'm totally lost. Can someone helps?
class mystructure{
private:
int value;
public:
mystructure(int v){
value=v;
}
void print(){
std::cout<<value<<std::endl;
}
std::string get_Value(){
return std::to_string(value);
}
};
int main(void) {
std::map<std::string, mystructure> mymap;
std::vector<mystructure> v = std::vector<mystructure>();
v.push_back(*(new mystructure(17)));
v.push_back(*(new mystructure(12)));
v.push_back(*(new mystructure(23)));
for (int i=0;i<v.size();i++) {
mystructure temp=v.at(i);
mymap.insert(temp.get_Value(),temp);//compilation error
}
return 0;
}
Because std::map::insert accepts std::map::value_type (i.e. std::pair<const Key, T>) as its parameter.
You could use:
mymap.insert(std::pair<const std::string, mystructure>(temp.get_Value(), temp));
or
mymap.insert(std::make_pair(temp.get_Value(), temp));
or
mymap.insert({temp.get_Value(), temp});
LIVE
Related
I'm trying to sort sets by value rather than keys. I keep running into the illegal indirection issue. The error occurs everytime I try to insert through the LRU cache. I assumed the issue had to do with not using pointers so I converted a and b to pointers instead but it didn't work.
struct comp {
bool operator ()(const pair<int, int>& a, const pair<int, int>& b) {
return a.second < b.second;
}
};
typedef set<pair<int, int>, comp> S;
struct LRUCache {
S cache;
typedef S::iterator it;
int cap;
LRUCache(int capacity) {
cap = capacity;
}
int get(int key) {
}
void setC(int key, int value) {
cache.insert(key, value);
}
void initialize() {
vector<int> temp{ 5,20,35,20,83,17,5,1,0,239,242,42 };
for (int i = 0; i < temp.size(); i++) {
setC(i, temp[i]);
}
}
};
int main()
{
LRUCache test(5);
test.initialize();
test.setC(1, 5);
test.setC(12, 20);
return 0;
}
The issue is that your std::set consists of std::pair<int, int>, and you're not inserting that type into your set with this line:
cache.insert(key, value);
This calls the set::insert function that takes two parameters, and the compiler is trying to match the two int values you're passing with one of the overloads here that takes two parameters.
Instead what you want to do is call set::insert with a single parameter, namely the std::pair<int, int>.
Change the above line to this:
cache.insert({key, value});
or
cache.insert(std::make_pair(key, value));
Live Example
You could also have seen the issue more clearly if you used using or typedef for the std::pair.
typedef std::pair<int, int> IntPair;
typedef std::set<IntPair, comp> PairSet;
//...
PairSet cache;
//...
cache.insert(IntPair(key, value));
You know that you want to insert IntPair's into the set, thus the code above would have compiled with no issue.
I've been trying for the last three day to figure out how to implement a generic way of getting the value out of a boost::variant<...>, but it's been quite difficult.
Here is the solution I could come up with, which it not at all generic:
#include <iostream>
#include "boost\variant\variant.hpp"
using MyVariant = boost::variant<int, std::string>;
class VariantConverter : public boost::static_visitor<>
{
private:
mutable int _int;
mutable std::string _string;
static VariantConverter apply(MyVariant& v)
{
VariantConverter res;
v.apply_visitor(res);
return res; // copy will be elided, right?
}
public:
void operator()(int& i) const
{
_int = i;
}
void operator() (std::string& s) const
{
_string = s;
}
static int to_int(MyVariant v)
{
return apply(v).from_int();
}
static std::string to_string(MyVariant v)
{
return apply(v).from_string();
}
int from_int()
{
return _int;
};
std::string from_string()
{
return _string;
};
};
int main()
{
using namespace std;
MyVariant v = 23;
int i = VariantConverter::to_int(v);
cout << i << endl;
v = "Michael Jordan";
std::string s = VariantConverter::to_string(v);
cout << s.c_str() << endl;
cin.get();
return 0;
}
I'd appreciate it if someone could guide me towards a better solution.
Or perhaps someone could explain to me the rationale behind this:
if I declare a:
using MyVariant = boost::variant<int, std::string>;
and then a:
ConverterToInt : basic_visitor<int> {
public:
int operator() (int i) { return i; };
};
Why is it that when I try to apply the ConverterToInt to a MyVariant as such:
ConverterToInt cti;
MyVariant i = 10;
i.apply_visitor(cti);
I get a compiler error about trying to find a operator() that takes a std::string?
It seems to me that apply_visitor is trying to call an operator() for each of the types MyVariant can take. Is that so? If it is, why? How can i avoid this behavior?
Cheers!
You can avoid the error message by telling ConverterToInt what to do with a std::string. You might know that i can't be a std::string but it's unreasonable to expect the compiler to know that (and if it is true, why are you using a variant?).
apply_visitor will only call the correct operator() method, but it decides at run time, and the compiler needs to have all the possibilities covered to generate the code.
MyVariant iv = 10;
int i = boost::get<int>(iv);
boost::variant does not "call" each operator() of an interface when invoked, but it must be able to. That's the entire point. A variant can hold any of the template types, so if you want to define an operation on it, you must specify somewhere what that operation means for each type.
I'm confused by the following code, why it cannot be successfully compiled?
class Test {
public:
int GetValue( int key ) const
{
return testMap[key];
}
map<const int, const int> testMap;
};
There is always a compling error:
error C2678: binary '[': no operator found which takes "const std :: map <_Kty,_Ty>" type of the left operand operator (or there is no acceptable conversion).
I've tried to put const qualifier everywhere but it still couldn't pass. Could you tell me why?
operator[] is not const, because it inserts an element if one doesn't already exist with the given key. find() does have a const overload, so you can call it with a const instance or via a const reference or pointer.
In C++11, there is std::map::at(), which adds bounds checking and raises an exception if an element with the given key is not present. So you can say
class Test {
public:
int GetValue( int key ) const
{
return testMap.at(key);
}
std::map<const int, const int> testMap;
};
Otherwise, use find():
int GetValue( int key ) const
{
auto it = testMap.find(key);
if (it != testMap.end()) {
return it->second;
} else {
// key not found, do something about it
}
}
You got an excellent answer by juanchopanza
Just wanted to show a boost way to return something that's not valid
with boost::optional you can return empty type
#include<boost\optional.hpp>
...
boost::optional<int> GetValue(int key){
auto it = testMap.find(key);
if (it != testMap.end()) {
return it->second;
} else {
return boost::optional<int>();
}
}
boost::optional<int> val = GetValue(your_key);
if(!val) //Not empty
{
}
Consider the following:
struct A
{
int i;
double d;
std::string s;
};
std::list<A> list_A;
I'd like to copy all the elements of list_A to a map such that every pair in the map will consist of an element from list_A as value and its string s as key. Is there a way of doing it that is more elegant than looping through the list and insert each element along with its string as key to the map?
I love standard library algorithms and lambdas but it doesn't get much simpler than:
for (const A& value : list_A) {
map_A.insert(std::make_pair(value.s, value));
}
The other methods are doing the equivalent of this code and this loop is readable and just as fast.
This should get you the idea of how to use transform:
std::pair<std::string, A> pairify(const A& a) { return std::make_pair(a.s, a); }
std::transform(list.begin(), list.end(), std::inserter(map, map.end()), pairify);
The reason to use the inserter is:
An insert interator is a special type of output iterator designed to allow algorithms that usually overwrite elements (such as copy) to instead insert new elements automatically at a specific position in the container.
Sorry answered too quickly last time without details, here is a compilable code.
struct A
{
int i;
double d;
std::string s;
};
std::list<A> list_A;
std::pair<std::string, A> convert(const A &x) {
return make_pair(x.s,x);
}
int main() {
std::map<std::string,A> out;
std::transform(list_A.begin(), list_A.end(), std::inserter(out,out.end()),convert);
}
I may store it in a set: in this way there would not be data duplication in the map (s itself):
struct A
{
bool operator < (const A& r_) const { return (s < r_.s); }
int i;
double d;
std::string s;
};
std::list<A> list_A;
std::set<A> set_A;
for ( std::list<A>::const_iterator itr = list_A.begin(); itr != list_A.end(); ++itr ) {
if ( ! set_A.insert(*itr).second ) {
// Handle duplicated elements
}
}
I may keep the loop: in this way you could handle duplicated elements correctly.
If you use C++11 you can use lambda function with capture:
std::map<std::string, A> m;
std::list<A> l;
std::for_each(l.begin(), l.end(),
[&](const A& a) {
m.insert(std::make_pair(a.s, a));
});
I would like to have a struct (or something similar) in C++, that will allow access to its members dynamically. It should have a generic getter and setters that receive the member name as a string, and return some sort of variant type (e.g. boost::variant).
I was thinking it could be implemented using boost::fusion::map, by adding a string representing the name of each member, and building an STL map between strings and getter or setter functions. I don't want to reinvent the wheel, so I was hoping something similar already existed.
What do you think? Would my idea work? Do you know other ways to accomplish my goal?
fusion is an approach, but why not store your "fields" in a std::map keyed by a std::string, where the payload is the boost::variant...
i.e.
struct generic
{
std::map<std::string, boost::variant<foo, bar, bob, int, double> > _impl;
};
and then you can just lookup the key in your getter/setter...
heck, wrap the variant in an optional and you could have optional fields!
a more complex example:
class foo
{
public:
typedef boost::variant<int, double, float, string> f_t;
typedef boost::optional<f_t&> return_value;
typedef map<string, return_value> ref_map_t;
foo() : f1(int()), f2(double()), f3(float()), f4(string()), f5(int())
{
// save the references..
_refs["f1"] = return_value(f1);
_refs["f2"] = return_value(f2);
_refs["f3"] = return_value(f3);
_refs["f4"] = return_value(f4);
_refs["f5"] = return_value(f5);
}
int getf1() const { return boost::get<int>(f1); }
double getf2() const { return boost::get<double>(f2); }
float getf3() const { return boost::get<float>(f3); }
string const& getf4() const { return boost::get<string>(f4); }
int getf5() const { return boost::get<int>(f5); }
// and setters..
void setf1(int v) { f1 = v; }
void setf2(double v) { f2 = v; }
void setf3(float v) { f3 = v; }
void setf4(std::string const& v) { f4 = v; }
void setf5(int v) { f5 = v; }
// key based
return_value get(string const& key)
{
ref_map_t::iterator it = _refs.find(key);
if (it != _refs.end())
return it->second;
return return_value();
}
template <typename VT>
void set(string const& key, VT const& v)
{
ref_map_t::iterator it = _refs.find(key);
if (it != _refs.end())
*(it->second) = v;
}
private:
f_t f1;
f_t f2;
f_t f3;
f_t f4;
f_t f5;
ref_map_t _refs;
};
int main(void)
{
foo fancy;
fancy.setf1(1);
cout << "f1: " << fancy.getf1() << endl;
fancy.set("f1", 10);
cout << "f1: " << fancy.getf1() << endl;
return 0;
}
You are asking for Reflection in C++ which I think is not available. You will have to come up with something of your own.
What I did for this was a boost::cons-like type-list that contains my members and some kind of description. I then build this mapping by successively adding my members to a "meta-info" data structure by "chained" function calls. The whole thing looks very similar to defining a class in boost.python. If you actually use boost::cons, it should also work as a sequence in boost.fusion, so you can iterate nicely over your data. Maybe you can use a boost.fusion map instead to get log(n) access times at run-time, but it seems their size is limited until variadic templates are available.