Implicit operator overloading with boost::variant C++ - c++

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).

Related

CPP: Use of deleted function

I am trying to sort a vector that contains custom struct entries using a lambda function in c++ . But I get prompted the following error message
error: use of deleted function ‘dummy_struct& dummy_struct::operator=(const dummy_struct&)
The code looks like the following:
#include <regex>
struct dummy_struct
{
dummy_struct(std::string name, int64_t value_a) :
name(name),
value_a(value_a)
{}
const std::string name;
const int64_t value_a;
int ExtractNumberFromName(std::regex key)
{
int retval;
std::cmatch match;
std::regex_search(this->name.c_str(),match,key);
retval=std::stoi(match[0],nullptr);
return retval;
}
};
void SortByCustomKey(const std::vector<dummy_struct> collection, std::regex key)
{
auto compare = [key](dummy_struct a, dummy_struct b)
{
return a.ExtractNumberFromName(key) > b.ExtractNumberFromName(key)
};
std::sort(std::begin(collection),std::end(collection),compare);
}
int main()
{
std::vector<dummy_struct> test;
test.push_back(dummy_struct("Entry[1]",1));
test.push_back(dummy_struct("Entry[2]",2));
test.push_back(dummy_struct("Entry[3]",3));
SortByCustomKey(test,std::regex("[0-9]+"));
}
What am I missing here?
std::sort sorts vector by swapping it's elements in place.
This requires for your class to implement copy assignment operator (or move assignment), which compiler won't generate for you due to const fields in the class. For your example the only solution seems to remove the const qualifiers from the fields. If you don't want them to be modified just make them private and don't provide (public) setters.
If they absolutely must stay there and you just want to get your values in sorted order you can use a different structure or store pointers in the vector.
Another solution is to write a custom swap implementation for your class that would const_cast away the qualifiers of the fields for the purpose of the assignment, although this is usually a bad code smell.

return an array of void*

I am building a C++ program that needs to store a map of strings to function pointers. However, every function may have different return types and parameters. The way I am attempting to solve this problem is by creating the functions as taking an array of void pointers and returning an array of void pointers, and then casting the arguments and return values as needed.
To figure out how this would work, I'm trying to build a simple dummy, but can't get it to compile. I've tried a number of things, but I keep getting different errors. here's an example:
#include <string>
#include <iostream>
#include <map>
using namespace std;
void** string2map(void** args){
//takes a string of the form "key:value;key:value;..." and returns a map<string,string>
string st = *((string**) args)[0];
map<string, string> result = map <string, string>();
//code doesnt matter
return (void*) &((void*) &result);
}
int main(){
string test = "hello:there;how:are you?";
map<string, string> result = *(map<string, string>**)string2map((void*) &((void*) &test))[0];
return 0;
}
when I try to compile, I get:
void.cpp: In function 'void** string2map(void**)':
void.cpp:12:34: error: lvalue required as unary '&' operand
void.cpp: In function 'int main()':
void.cpp:17:89: error: lvalue required as unary '&' operand
Obviously there are plenty of things wrong here, but I really just don't know where to start. Can anyone either show me what's wrong with the code above, or give me an alternative to the way I am currently doing it?
NOTE
The reason I am returning a void** instead of just void* is that there might be a circumstance where I need to return multiple values of different types. An example would be if, above, I wanted to return both the resulting map AND the number of entries in the map. I haven't even gotten to the point of figuring out how to construct that array yet, though.
EDIT
So based on the responses so far, it seems pretty clear that this is the wrong way of solving this problem. With that in mind, can anyone suggest a better one? I need to be able to store the various function in a single map, which means I need to be able to define a single data type to functions that take and return different types. And it IS important to be able to return multiple values.
You're converting a map<string,string> to a void**, returning it then converting it back to a map<string,string. Why not just return a map<string,string>? It's also called string2map which implies you will only ever call it with a string (backed up by the fact you pass in a string, which is converted to a void** then converted straight back). Unless you have a good reason to convert to and from void** all over the place this is probably what you need:
#include <string>
#include <iostream>
#include <map>
using namespace std;
map<string, string> string2map(string st){
map<string, string> result = map <string, string>();
//code doesnt matter
return result;
}
int main(){
string test = "hello:there;how:are you?";
map<string, string> result = string2map(test);
return 0;
}
EDIT:
I've just reread your question. You might want to look up Generalised Functors and look at Boost's std::function as possible solutions to this problem. It's possible to change the return type of a function via a wrapper class, something like:
template< class T >
class ReturnVoid
{
public:
ReturnVoid( T (*functor)() ) : m_functor( functor ) {}
void operator() { Result = functor(); }
private:
T (*m_functor)();
T Result;
};
// Specialise for void since you can't have a member of type 'void'
template<>
ReturnVoid< void >
{
public:
ReturnVoid( T (*functor)() ) : m_functor( functor ) {}
void operator() { functor(); }
private:
T (*m_functor)();
};
Using this as a wrapper might help you store functors with different return types in the same array.
Ignoring my own horror at the idea of blatantly throwing type safety to the wind, two things spring immediately to mind.
First, what exactly do you think will be pointed to when string2map goes out of scope?
Second is that you don't have to cast to void*. Void* gets special treatment in C++ in that anything can be cast to it.
If you insist on trying to push this, I'd start by changing the return type to void, and then take the void* as an input parameter to your function.
For example:
void string2map(void* args, void* returnedMap);
This way you'd have to instantiate your map in a scope that will actually have a map to point to.
$5.3.1/3 - "The result of the unary & operator is a pointer to its
operand. The operand shall be an lvalue or a qualifiedid."
$5.3.1/2 - "The result of each of the following unary operators is a
prvalue."
So, in effect you are trying to take the address of an rvalue which is not allowed.
Further, C++ does not allow to return an array.
So, you really want to start looking at what you want. Return the map by value instead is one definite option.
The way I am attempting to solve this problem is by creating the functions as taking an array of void pointers and returning an array of void pointers, and then casting the arguments and return values as needed.
That's (really really) bad. Have a look instead at std::function and std::bind - those should cover differences between function signatures and bound arguments in an elegant way.
The reason I am returning a void** instead of just void* is that there might be a circumstance where I need to return multiple values of different types.
Then return an object that contains the values. For generics have a look at std::tuple or boost::any.
Here's some code:
void function1(int, const char); // defined elsewhere
std::tuple<int,int> function2(std::string&); // defined elsewhere
std::map<std::string,std::function<void(void)>> functionmap;
functionmap.insert( std::make_pair("function1", std::bind(&function1, 2, 'c')) );
std::tuple<int,int> result;
functionmap.insert( std::make_pair("function2", [&result] {
result = function2("this is a test"); } );
// call function1
functionmap["function1"]();
// call function2
functionmap["function2"](); // result will now contain the result
// of calling function2
Is this what you tried to do?
int Foo(int a) { return a; }
typedef int (*FooFunc)(int);
void Bar(){}
typedef std::map<std::string, void*> FunctionMap;
// you should use boost::any or something similar instead of void* here
FunctionMap CreateFunctionMap(const std::string& args)
{
FunctionMap result;
result["Foo"] = &Foo;
result["Bar"] = &Bar;
return result;
}
void Call(FunctionMap::const_reference functionInfo)
{
// #hansmaad The key will give information on the signatures.
// there are a few distinct options, so it will be a conditional
// with a couple of clauses.
if (functionInfo.first == "Foo")
{
auto f = static_cast<FooFunc>(functionInfo.second);
std::cout << f(42);
}
else if (functionInfo.first == "Bar")
{
/* */
}
}
int main()
{
auto functions = CreateFunctionMap("...");
std::for_each(begin(functions), end(functions), Call);
}
#hansmaad The key will give information on the signatures. there are a few distinct options, so it will be a conditional with a couple of clauses. – ewok 33 mins ago
In that case, the typical solution is like this:
typedef void (*func_ptr)();
std::map<std::string, func_ptr> func_map;
map<string,string> string2map(string arg){
//takes a string of the form "key:value;key:value;..." and returns a map<string,string>
map<string, string> result = map <string, string>();
//...
return result;
}
// ...
// Add function to the map
func_map["map<string,string>(string)" = (func_ptr)string2map;
// Call function in the map
std::map<std::string, func_ptr>::iterator it = ...
if (it->first == "map<string,string>(string)")
{
map<string,string> (*func)(string) = (map<string,string>(*)(string))it->second;
map<string,string> result = func("key1;value1;key2;value2");
}
For brevity, I have used C-style casts of the function pointers. The correct C++ cast would be reinterpret_cast<>().
The function pointers are converted to a common type on insertion into the map and converted back to their correct type when invoking them.

Store struct in a map; Checking if a struct exist inside a map

Q#1) Struct below doesn't want to be copied and gives compilation errors - why and how to deal with it?
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct person
{
person(string n)
:name(n)
{}
string name;
};
int main()
{
map<string, person> my_map;
my_map["one"] = person("Tom");
return 0;
}
Q#2) We can avoid the problem above by omitting the struct constructor "person(const string& n)" and assigning struct values one by one:
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct person
{
string name;
};
int main()
{
map<string, person> my_map;
person p;
p.name = "Tom";
my_map["one"] = p;
return 0;
}
So, let's say I do it this way, and after storing many persons in the map I want to check if a particular person exists inside a map. As I know the correct way of doing it is:
if(my_map.find("one") == my_map.end()) { //it doesn't exist in my_map }
else {//it exists}
But this as I understand will iterate through the whole map one by one, won't it? If yes, then is it okay to do it like:
using namespace std;
struct person
{
string name;
string identifier; // <--
};
int main()
{
map<string, person> my_map;
person p;
p.name = "Tom";
p.identifier = "something"; // <--
my_map["one"] = p;
if(my_map["unknown"].identifier == "something") // <--
cout << "Found" << endl;
else
cout << "Not found" << endl;
return 0;
}
By doing this we avoid iterating, and possibility that garbage in the memory will match our identifier is... small I guess, especially if we use some hash.
So is it okay (secure) doing like that?
1) The code in your first example fails to compile because of the following expression:
my_map["one"]
my_map["one"] constructs a std::string from "one", and passes it to std::map::operator[]. map::operator[] ensures that a value is mapped to the supplied key (by associating the key with a default-constructed value if it is not already associated with a value) and returns a reference to that value.
This does not compile, because person does not have a default constructor (A "default constructor" is a constructor which takes no arguments).
There are several ways to fix this problem.
One way is the way that you took - removing the constructor. It works because if you do not supply any constructors, a default constructor will be implicitly defined.
Another way is to explicitly define a default constructor for person:
struct person
{
person():name(){} //or person()=default; if your compiler supports this
person(string n)
:name(n)
{}
string name;
};
Another way is to not use operator[] at all, and to instead use map::insert, as follows:
auto pair(my_map.insert(std::make_pair(std::string("one"),person("Tom"))));
if (!pair.second) {
*pair.first = person("Tom");
}
2) The correct way to find an element in the map is (as you said) to use:
if(my_map.find("one") == my_map.end()) {/*it doesn't exist in my_map*/}
else {/*it exists*/}
This does not inspect every element in the map - in fact it may only inspect O(log(map.size())) elements.
Your fears are totally unfounded, this is the correct way to find an element in the map, however the way in which you continue suggests a severe misunderstanding about what operator[] does.
You ask "what is the probability that my_map["unknown"].identifier == "something" will return true if "unknown" does not exist in the map?".
The answer to this is that there is no chance whatsoever of this returning true, because if no value with the key std::string("unknown") exists in the map, then operator[] will associate std::string("unknown") with a default constructed person, and so identifier will be an empty string.
First of all, since you have a constructor, you need to provide a default constructor. This is because C++ standard library containers use value semantics. So the map needs to be able to copy values, assign them, and default construct them. Since you provide a constructor, the compiler does not synthesize the default constructor. This is a default constructor that does nothing:
person() {} // default constructs string, so no special aciton required.
Particularly in the case of std::map, operator[] returns a reference to a default constructed value when an element with the key does not already exist in the map:
my_map["one"] = p; // creates *default* person, then *assigns* it the value of p.
Second, concerning your question about searching the map, std::map, search has logarithmic complexity and is typically implemented as a self-balancing binary tree. So when you search you do not traverse the whole map. And since accessing via operator[] introduces new elements when the searched key doesn't exist, the form using find() is the canonical way to do it.
Since you mentioned hashing, C++11 provides std::unordered_map, and tr1 and boost have hash_map. These use hash functions perform the search is constant time. Whether it is worth using it or not depends on factors such as the size of your map. The constant time could be larger than the logarithmic time taken to search a small map.
Note:
If you want to use your struct as key, or want to insert it into one of the standard library sets, you have further requirements:
maps: You need to provide strict weak ordering, for the key, either via a less-than operator for your class, or a custom comparator functor. If you were to use person as a key, you woul dneed something like:
bool operator<(const person& rhs) const { return name < rhs.name; }
unordered_ or hash maps: You must provide both a hash function and an equality comparison for the key, either via an operator== or a functor. .

Setter and Getter method for map

string var;
void setvar(string ivar)
{
var=ivar;
}
string getVar() const
{
return var;
}
as same way how can i write setter and getter method for a map like this
std::map varmap;
You can write a getter or setter for a field that's a std::map just as you would any other field - just have the getter return a std::map and have the setter accept a std::map.
Of course, if you have a field that's a std::map that you're trying to use getters and setters on, that might suggest that there's a better way to structure the program. Can you provide more details about what you're trying to do?
EDIT: The above answer is for a slightly different question than the one you asked. It seems like what you're interested in is
Given a class with a std::map as a data member, write a function to set a given key/value pair and a function to return the value associated with a given key.
The setter logic for this is not too hard - you just write a function that takes in the key and value and associates the key with the value. For example:
void put(const string& key, const string& value) {
varmap[key] = value;
}
Writing a getter is trickier because there's no guarantee that there's a value associated with a particular key. When this happens, you have multiple options.
You could return a sentinel value. For example, you might return an empty string if the given value isn't stored in the map anywhere. This makes the code for using the function easier to read, but risks using an invalid value in code.
You could throw an exception. This would be good if it represents a serious error for the given value not to exist. This has the drawback that if you look up a value, you always need to try/catch the logic to avoid propagation of errors.
You could associate a default value with the key, then hand that back. If you're writing a program that represents a music library, for example, you might hand back "(none)" or "(unknown)" if you tried to look up the artist for a song on which you have no data, for example.
No one of these approaches works best, and you'll need to think over which is most appropriate to your particular circumstance.
Entries in a std::map<Key, Value> must have a key and a value. The normal way of getting and setting them is:
my_map[a_key] = new_value; // set
do_something_with(my_map[a_key]); // get and use...
If you want to add new functions, they probably wouldn't look like what you're proposing because:
your set is only given one parameter despite needing a key and value (admittedly, you could adopt some convention like having the first ':' or '=' separate them), and
the get() function doesn't provide any key.
You could instead have something more like:
void set(const Key&, const Value&);
std::string get(const Key&) const;
But, even if you have write permissions to do so, you shouldn't add that directly in the map header file - all C++ programs compiled on that computer will share that file and won't expect it to be modified. Any small mistake could cause trouble, and if you ship your program to another computer you won't be able to compile it there without making a similar modification - if that computer uses a different C++ compiler the necessary details of that modification may be slightly different too.
So, you can either write your own (preferably templated) class that derives from (inherits) or contains (composition) a std::map, providing your functions in your custom class. An inheritance based solution is easier and more concise to write:
template <typename Key, typename Value>
struct My_Map : std::map<Key, Value>
{
My_Map(...); // have to provide any non-default constructors you want...
void set(const Key& key, const Value& value) { operator[](key) = value; }
// if you want entries for non-existent keys to be created with a default Value...
Value& get(const Key& key) { return operator[](key); }
--- OR ---
// if you want an exception thrown for non-existent keys...
Value& get(const Key& key) { return at(key); }
const Value& get(const Key& key) const { return at(key); }
};
This is slightly dangerous if you're planning to pass My_Maps around by pointer and accidentally end up with a "new My_Map" pointer that's later deleted as a std::map pointer, as in:
void f(std::map<int, string>* p) { /* use *p */ delete p; }
My_Map<int, string>* p = new My_Map<int, string>;
f(p);
Still, in most programs there's no real danger of accidentally disposing of a map like this, so go ahead and do it.
Further, and this is the kind of thinking that'll make me unpopular with the Standard-fearing purists around here - because My_Map hasn't added any data members or other bases, the std::map<> destructor probably does all the necessary tear-down even though it's technically Undefined Behaviour. I'm NOT encouraging you to ignore the issue (and would consider it unprofessional in a job requiring robustness), but you can at least rest a little easier. I'd be curious to hear from anyone with any compiler/settings where it demonstrably doesn't operate safely.
If you use composition, you'll have to write your own "forwarding" functions to let you use My_Map like a std::map, accessing iterators, find, erase, insert etc.. It's a pain.
Setter and getter for std::map is no different except that you need to pass the necessary parameters for the setter. Assume if I have a struct and has a member variable whose type is std::map, whose key is of type char and data is of type int. Method signatures would be of the format -
void setEncode( char* key, int* data, const int& size ); Because, std::map requires a key, data and sizes of these arrays being passed. With out knowing size, it is unknown as how far to insert the elements in to the container.
std::map<char, int> getEncode() const ; const key word signifies it a non-modifying member function. Because it's functionality is to just return a variable of type std::map.
Example -
struct myMap
{
std::map<char, int> encode;
void setEncode( char* key, int* data, const int& size );
std::map<char, int> getEncode() const ;
};
void myMap::setEncode( char *key, int* data, const int& size )
{
int i=0;
while( i < size )
{
encode.insert(std::pair<char, int>(key[i], data[i]));
++i ;
}
}
std::map<char, int> myMap::getEncode() const
{
return encode;
}
Results IdeOne. This should give you an idea, but should also follow the general rules what #templatetypedef, #tony suggested.
Do you want to set a key value pair in an existing map(probably that's what you want) or create a new map itself?
void setvar(string key, int value)
{
myMap[key] = value;
}
int getVar(string key) const
{
return myMap[key];
}
where int and string are interchangeable
For latter you'll probably have to interate over all map values for setting and getter should be just to return that map pointer.

Recursion problem overloading an operator

I have this:
typedef string domanin_name;
And then, I try to overload the operator< in this way:
bool operator<(const domain_name & left, const domain_name & right){
int pos_label_left = left.find_last_of('.');
int pos_label_right = right.find_last_of('.');
string label_left = left.substr(pos_label_left);
string label_right = right.substr(pos_label_right);
int last_pos_label_left=0, last_pos_label_right=0;
while(pos_label_left!=string::npos && pos_label_right!=string::npos){
if(label_left<label_right) return true;
else if(label_left>label_right) return false;
else{
last_pos_label_left = pos_label_left;
last_pos_label_right = pos_label_right;
pos_label_left = left.find_last_of('.', last_pos_label_left);
pos_label_right = right.find_last_of('.', last_pos_label_left);
label_left = left.substr(pos_label_left, last_pos_label_left);
label_right = right.substr(pos_label_right, last_pos_label_right);
}
}
}
I know it's a strange way to overload the operator <, but I have to do it this way. It should do what I want. That's not the point.
The problem is that it enter in an infinite loop right in this line:
if(label_left<label_right) return true;
It seems like it's trying to use this overloading function itself to do the comparision, but label_left is a string, not a domain name!
Any suggestion?
typedef just gives another name for a type. It does not create a distinct type. So in effect, you're overloading operator < for string.
If you want to create a distinct type, then you can try
struct domain_name {
string data;
// ...
};
and work with that.
Typedef doesn't work like this. Typedef simply defines an alias for the type - it is still a string. In order to do this, you would need a new type instead. You should do this anyway. Your operator is overloading the comparison operator for all strings.
Your typedef doesn't create a new type. It just creates a new name to refer to the same type as before. Thus, when you use < inside your operator function on two strings, the compiler just uses the same operator it's compiling because the argument types match.
What you may wish to do instead is define an entirely new function:
bool domain_less(domain_name const& left, domain_name const& right);
Then use that function in places that call for a comparison function, such as std::sort. Most of the standard algorithms will use < by default, but allow you to provide your own predicate function instead. You may need to use std::ptr_fun to wrap your function. You can also write your own functor object; it's typical to descend from std::binary_function in that case. (Check out the <functional> header.)