Creating a Variant class and std::map<Variant, Variant> - c++

I craeted a simple Variant class to store string, integer, double, etc. I'm trying to use a map of type std::map<Variant, Variant> but I'm getting this strange error:
In file included from /usr/include/c++/7/string:48:0,
from /home/dev/proj/cpp/common/Variant.h:3,
from /home/dev/proj/cpp/common/Event.h:3,
from /home/dev/proj/cpp/common/Event.cpp:1:
/usr/include/c++/7/bits/stl_function.h: In instantiation of 'constexpr bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Variant]':
/usr/include/c++/7/bits/stl_map.h:511:32: required from 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](std::map<_Key, _Tp, _Compare, _Alloc>::key_type&&) [with _Key = Variant; _Tp = Variant; _Compare = std::less<Variant>; _Alloc = std::allocator<std::pair<const Variant, Variant> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = Variant; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = Variant]'
/home/dev/orwell/cpp/common/Event.cpp:33:18: required from here
/usr/include/c++/7/bits/stl_function.h:386:20: error: no match for 'operator<' (operand types are 'const Variant' and 'const Variant')
{ return __x < __y; }
~~~~^~~~~
This is my Variant class:
class Variant
{
public:
enum class Type
{
Integer,
Double,
String
};
Variant()
{
}
Variant(int integer)
{
this->type = Type::Integer;
setInteger(integer);
}
Variant(std::string string)
{
this->type = Type::String;
setString(string);
}
Variant(double _double)
{
this->type = Type::Double;
setDouble(_double);
}
Type type;
This is where the error is happening:
void Event::add(std::string key, std::string value) {
this->map[key] = Variant(value); //problem here
}

std::map is a sorted array. To do that it uses the < operator.
Thus, if you want to use Variant in a map (I believe this only applies to keys), you will need to supply an operator<() for it. You can find some examples here.
Or, you'll need a comparison function. That can work too.

Related

Unable to create a map of a class in C++

I'm not able to create a map of a certain class in C++.
Here is an example of what I'm talking about:
#include <iostream>
#include <map>
using namespace std;
class A {
private:
string name;
public:
A(){}
A(string name) : name(name){}
A(A& a) : name(a.name){}
~A(){}
string getName() { return name; }
};
int main() {
A a("a_name");
map<string, A> mapa;
mapa["a_name"] = a;
return 0;
}
When I compile the code, it gives me the following error:
In file included from /usr/include/c++/8/bits/stl_algobase.h:64,
from /usr/include/c++/8/bits/char_traits.h:39,
from /usr/include/c++/8/ios:40,
from /usr/include/c++/8/ostream:38,
from /usr/include/c++/8/iostream:39,
from prog.cpp:1:
/usr/include/c++/8/bits/stl_pair.h: In instantiation of ‘struct std::pair<const std::__cxx11::basic_string<char>, A>’:
/usr/include/c++/8/bits/stl_map.h:517:10: required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](std::map<_Key, _Tp, _Compare, _Alloc>::key_type&&) [with _Key = std::__cxx11::basic_string<char>; _Tp = A; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, A> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = A; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::__cxx11::basic_string<char>]’
prog.cpp:20:15: required from here
/usr/include/c++/8/bits/stl_pair.h:303:17: error: ‘constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const std::__cxx11::basic_string<char>; _T2 = A]’ declared to take const reference, but implicit declaration would take non-const
constexpr pair(const pair&) = default;
^~~~
Here is the code in ideone: https://www.ideone.com/sYsxcO
I need the map to save the object itself, and not just a pointer to it (in this case, the A objects).

How to find the keys of a map within a string array?

Hello I am trying to add the values of the map to the int variable named "total", once the corresponding keys are found within the string array. For an example "aab" will give a total of 5 and "bbc" will give a total of 7. I tried running the code, but it wouldn't work. I instead got the following error:
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_map.h:1221:2: note: template argument deduction/substitution failed:
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_map.h: In substitution of 'template<class _Kt> decltype (((const std::map<char, int>*)this)->std::map<char, int>::_M_t.std::_Rb_tree<char, std::pair<const char, int>, std::_Select1st<std::pair<const char, int> >, std::less<char>, std::allocator<std::pair<const char, int> > >::_M_count_tr<_Kt, _Req>(__x)) std::map<char, int>::count<_Kt>(const _Kt&) const [with _Kt = std::__cxx11::basic_string<char>]':
Maps1.cpp:34:29: required from here
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_map.h:1221:2: error: no matching function for call to 'std::_Rb_tree<char, std::pair<const char, int>, std::_Select1st<std::pair<const char, int> >, std::less<char>, std::allocator<std::pair<const char, int> > >::_M_count_tr(const std::__cxx11::basic_string<char>&) const'
In file included from C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/map:60,
from Maps1.cpp:1:
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_tree.h:1250:2: note: candidate: 'template<class _Kt, class _Req> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_count_tr(const _Kt&) const [with _Kt = _Kt; _Req = _Req; _Key = char; _Val = std::pair<const char, int>; _KeyOfValue = std::_Select1st<std::pair<const char, int> >; _Compare = std::less<char>; _Alloc = std::allocator<std::pair<const char, int> >]'
_M_count_tr(const _Kt& __k) const
^~~~~~~~~~~
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_tree.h:1250:2: note: template argument deduction/substitution failed:
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_tree.h:1247:9: error: no type named 'type' in 'struct std::__has_is_transparent<std::less<char>, std::__cxx11::basic_string<char>, void>'
typename _Req =
^~~~~~~~
Maps1.cpp:35:21: error: no match for 'operator[]' (operand types are 'std::map<char, int>' and 'std::__cxx11::string' {aka 'std::__cxx11::basic_string<char>'})
total += hashMap[array[j]];
^
In file included from C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/map:61,
from Maps1.cpp:1:
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_map.h:490:7: note: candidate: 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = char; _Tp = int; _Compare = std::less<char>; _Alloc = std::allocator<std::pair<const char, int> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = int; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = char]'
operator[](const key_type& __k)
^~~~~~~~
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_map.h:490:7: note: no known conversion for argument 1 from 'std::__cxx11::string' {aka 'std::__cxx11::basic_string<char>'} to 'const key_type&' {aka 'const char&'}
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_map.h:510:7: note: candidate: 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](std::map<_Key, _Tp, _Compare, _Alloc>::key_type&&) [with _Key = char; _Tp = int; _Compare = std::less<char>; _Alloc = std::allocator<std::pair<const char, int> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = int; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = char]'
operator[](key_type&& __k)
^~~~~~~~
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/stl_map.h:510:7: note: no known conversion for argument 1 from 'std::__cxx11::string' {aka 'std::__cxx11::basic_string<char>'} to 'std::map<char, int>::key_type&&' {aka 'char&&'}
I did a similar thing, but using a single string instead of a string array, and it worked.
I am a complete beginner in c++, and I am very confused. Please could someone explain the reason for this error and give me an alternative solution. Thank you very much for your time and effort. My code is shown below:
#include <map>
#include <iostream>
#include <string>
using namespace std;
int main(){
map<char, int> hashMap;
string array[] = {"aab", "ab", "bbc", "cab"};
hashMap['a'] = 1;
hashMap['b'] = 3;
hashMap['c'] = 1;
int total = 0;
for(int i = 0; i < array.size(); i++){
for(int j = 0; j < array[i].size(); j++){
if(hashMap.find(array[j]) != hashMap.end()){
total += hashMap[array[j]];
}
}
}
cout << total;
map<char, int> hashMap;
Your variable name is highly confusing. std::map is not a hashmap.
string array[] = {"aab", "ab", "bbc", "cab"};
...
for(int i = 0; i < array.size(); i++){
The problem here is that arrays do not have member functions. Yet, you are trying to call a member function size on an array.
You can use std::size instead:
for(int i = 0; i < std::size(array); i++){
Or you can use a range-for loops for better readability:
for(auto& str : array) {
for(char c : str) {
There is also a potential naming confusion because you shadow the standard name std::array that you had introduced to the global namespace with using namespace std; Don't use using namespace std;.
if(hashMap.find(array[j]) != hashMap.end()){
total += hashMap[array[j]];
The problem here is that keys of your map are char, but you are trying to search for a string. I suspect that you intended to write array[i][j] - use just c if you use the suggested range-for.
Furthermore, it is unnecessarily inefficient to do the lookup twice. Store the iterator so you can get the value from it without looking it up again:
auto it = hashMap.find(array[i][j]);
if(it != hashMap.end()){
total += it->second;

Mapping a pair to a struct

There's some code I've written which I have trouble with, but I've tried to write a simplified version of it to possibly reproduce the error I'm encountering:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
struct test{
float y;
};
typedef pair<int, int> intpair;
map<intpair, test> mp;
void func(test &obj){
obj.y = 23.5;
}
int main () {
test* obj = new test;
auto key = make_pair(1,1);
mp.insert(key, obj);
func(*obj);
//cout << *(obj->y);
delete obj;
return 0;
}
What I would like to do is map a pair to a custom struct test that I have created. I get the following error:
main.cpp: In function ‘int main()’:
main.cpp:22:22: error: no matching function for call to ‘std::map, test>::insert(std::pair&, test*&)’
mp.insert(key, obj);
^
In file included from /usr/include/c++/6/map:61:0,
from /usr/include/x86_64-linux-gnu/c++/6/bits/stdc++.h:81,
from main.cpp:2:
/usr/include/c++/6/bits/stl_map.h:731:7: note: candidate: std::pair, std::_Select1st >, _Compare, typename __gnu_cxx::__alloc_traits<_Allocator>::rebind >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const value_type&) [with _Key = std::pair; _Tp = test; _Compare = std::less >; _Alloc = std::allocator, test> >; typename std::_Rb_tree<_Key, std::pair, std::_Select1st >, _Compare, typename __gnu_cxx::__alloc_traits<_Allocator>::rebind >::other>::iterator = std::_Rb_tree_iterator, test> >; std::map<_Key, _Tp, _Compare, _Alloc>::value_type = std::pair, test>]
insert(const value_type& __x)
^~~~~~
/usr/include/c++/6/bits/stl_map.h:731:7: note: candidate expects 1 argument, 2 provided
/usr/include/c++/6/bits/stl_map.h:739:9: note: candidate: template std::pair, std::_Select1st >, _Compare, typename __gnu_cxx::__alloc_traits<_Allocator>::rebind >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(_Pair&&) [with _Pair = _Pair; = ; _Key = std::pair; _Tp = test; _Compare = std::less >; _Alloc = std::allocator, test> >]
insert(_Pair&& __x)
^~~~~~
/usr/include/c++/6/bits/stl_map.h:739:9: note: template argument deduction/substitution failed:
main.cpp:22:22: note: candidate expects 1 argument, 2 provided
mp.insert(key, obj);
^
In file included from /usr/include/c++/6/map:61:0,
from /usr/include/x86_64-linux-gnu/c++/6/bits/stdc++.h:81,
from main.cpp:2:
/usr/include/c++/6/bits/stl_map.h:752:7: note: candidate: void std::map<_Key, _Tp, _Compare, _Alloc>::insert(std::initializer_list >) [with _Key = std::pair; _Tp = test; _Compare = std::less >; _Alloc = std::allocator, test> >]
insert(std::initializer_list<value_type> __list)
^~~~~~
/usr/include/c++/6/bits/stl_map.h:752:7: note: candidate expects 1 argument, 2 provided
/usr/include/c++/6/bits/stl_map.h:781:7: note: candidate: std::map<_Key, _Tp, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::insert(std::map<_Key, _Tp, _Compare, _Alloc>::const_iterator, const value_type&) [with _Key = std::pair; _Tp = test; _Compare = std::less >; _Alloc = std::allocator, test> >; std::map<_Key, _Tp, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator, test> >; std::map<_Key, _Tp, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator, test> >; std::map<_Key, _Tp, _Compare, _Alloc>::value_type = std::pair, test>]
insert(const_iterator __position, const value_type& __x)
^~~~~~
/usr/include/c++/6/bits/stl_map.h:781:7: note: no known conversion for argument 1 from ‘std::pair’ to ‘std::map, test>::const_iterator {aka std::_Rb_tree_const_iterator, test> >}’
/usr/include/c++/6/bits/stl_map.h:792:9: note: candidate: template std::map<_Key, _Tp, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::insert(std::map<_Key, _Tp, _Compare, _Alloc>::const_iterator, _Pair&&) [with _Pair = _Pair; = ; _Key = std::pair; _Tp = test; _Compare = std::less >; _Alloc = std::allocator, test> >]
insert(const_iterator __position, _Pair&& __x)
^~~~~~
/usr/include/c++/6/bits/stl_map.h:792:9: note: template argument deduction/substitution failed:
main.cpp:22:22: note: cannot convert ‘key’ (type ‘std::pair’) to type ‘std::map, test>::const_iterator {aka std::_Rb_tree_const_iterator, test> >}’
mp.insert(key, obj);
^
In file included from /usr/include/c++/6/map:61:0,
from /usr/include/x86_64-linux-gnu/c++/6/bits/stdc++.h:81,
from main.cpp:2:
/usr/include/c++/6/bits/stl_map.h:807:9: note: candidate: template void std::map<_Key, _Tp, _Compare, _Alloc>::insert(_InputIterator, _InputIterator) [with _InputIterator = _InputIterator; _Key = std::pair; _Tp = test; _Compare = std::less >; _Alloc = std::allocator, test> >]
insert(_InputIterator __first, _InputIterator __last)
^~~~~~
/usr/include/c++/6/bits/stl_map.h:807:9: note: template argument deduction/substitution failed:
main.cpp:22:22: note: deduced conflicting types for parameter ‘_InputIterator’ (‘std::pair’ and ‘test*’)
mp.insert(key, obj);
Also, I'm sure that I'm going wrong in the way I access my obj's member y (cout statement commented out); How do I go about resolving these issues?
There are no overload of std::map::insert that takes a key and a value.
You can use operator[] to add a new element:
mp[key] = *obj;
Or std::map::insert_or_assign since C++17:
mp.insert_or_assign(key, *obj);
Another point is that type of obj is test* while the type of values of the map mp has type test. The pointer should be dereferenced (like my examples above) or the type of values should be changed to pointers to do this insertion.

How to define a map from function pointers to strings

I am trying to define a map from member function pointers to strings in C++. But the the compiler complains that operator < is not defined for member function pointers. Is there a way to do this?
Example code:
#include <map>
#include <string>
class foo;
typedef void (foo::*fooFunc)();
class foo {
public:
foo() {
myMap[func]="example function";
}
void func() {};
std::map<fooFunc,std::string> myMap;
};
Resulting error message:
In file included from C:/msys64/mingw64/include/c++/6.2.0/bits/stl_tree.h:65:0,
from C:/msys64/mingw64/include/c++/6.2.0/map:60,
from grr.cpp:1:
C:/msys64/mingw64/include/c++/6.2.0/bits/stl_function.h: In instantiation of 'constexpr bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = void (foo::*)()]':
C:/msys64/mingw64/include/c++/6.2.0/bits/stl_map.h:501:32: required from 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](std::map<_Key, _Tp, _Compare, _Alloc>::key_type&&) [with _Key = void (foo::*)(); _Tp = std::__cxx11::basic_string<char>; _Compare = std::less<void (foo::*)()>; _Alloc = std::allocator<std::pair<void (foo::* const)(), std::__cxx11::basic_string<char> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::__cxx11::basic_string<char>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = void (foo::*)()]'
grr.cpp:9:15: required from here
C:/msys64/mingw64/include/c++/6.2.0/bits/stl_function.h:386:20: error: invalid operands of types 'void (foo::* const)()' and 'void (foo::* const)()' to binary 'operator<'
{ return __x < __y; }
~~~~^~~~~
std::map requires a comparison operator for its keys. By default, it uses operator <. Since operator < is not defined for pointer-to-member types, you are getting this error.
To fix it you'll need to define a custom comparison operator and provide it as a parameter to std::map. Alternatively, use a different container.
From cppreference:
std::map is a sorted associative container that contains key-value
pairs with unique keys. Keys are sorted by using the comparison
function Compare. Search, removal, and insertion operations have
logarithmic complexity. Maps are usually implemented as red-black
trees
If you want options on how to write such a comparison operator, it has already been answered here.

Smart pointers and map in C++

I'm trying to execute this program with smart pointers:
//File user.h
#include <list>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <memory>
#include <map>
using namespace std;
class User {
string name;
int id;
public:
User(const string& name, int id) : name(name), id(id) {}
int getID() const {return id;}
~User(){}
};
//File main.c
#include "user.h"
using namespace std;
typedef std::shared_ptr<User> UserPtr;
typedef map<string, UserPtr> Dict;
int main()
{
Dict dict;
dict = new User("Adams", 666);
auto it = dict.find("Adams");
if (it == dict.end())
cout << "not found!" << endl;
else
cout << "id3: " << it->second->getID() << endl;
return 0;
}
I have tested it before with raw pointers (*) and it works. Nonetheless, when using smart pointers I get the following errors:
main.cpp: In function ‘int main()’:
main.cpp:15:10: error: no match for ‘operator=’ (operand types are ‘Dict {aka std::map<std::basic_string<char>, std::shared_ptr<User> >}’ and ‘User*’)
dict = new User("Adams", 666);
^
main.cpp:15:10: note: candidates are:
In file included from /usr/include/c++/4.8/map:61:0,
from user.h:10,
from main.cpp:3:
/usr/include/c++/4.8/bits/stl_map.h:264:7: note: std::map<_Key, _Tp, _Compare, _Alloc>& std::map<_Key, _Tp, _Compare, _Alloc>::operator=(const std::map<_Key, _Tp, _Compare, _Alloc>&) [with _Key = std::basic_string<char>; _Tp = std::shared_ptr<User>; _Compare = std::less<std::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::basic_string<char>, std::shared_ptr<User> > >]
operator=(const map& __x)
^
/usr/include/c++/4.8/bits/stl_map.h:264:7: note: no known conversion for argument 1 from ‘User*’ to ‘const std::map<std::basic_string<char>, std::shared_ptr<User> >&’
/usr/include/c++/4.8/bits/stl_map.h:279:7: note: std::map<_Key, _Tp, _Compare, _Alloc>& std::map<_Key, _Tp, _Compare, _Alloc>::operator=(std::map<_Key, _Tp, _Compare, _Alloc>&&) [with _Key = std::basic_string<char>; _Tp = std::shared_ptr<User>; _Compare = std::less<std::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::basic_string<char>, std::shared_ptr<User> > >]
operator=(map&& __x)
^
/usr/include/c++/4.8/bits/stl_map.h:279:7: note: no known conversion for argument 1 from ‘User*’ to ‘std::map<std::basic_string<char>, std::shared_ptr<User> >&&’
/usr/include/c++/4.8/bits/stl_map.h:300:7: note: std::map<_Key, _Tp, _Compare, _Alloc>& std::map<_Key, _Tp, _Compare, _Alloc>::operator=(std::initializer_list<std::pair<const _Key, _Tp> >) [with _Key = std::basic_string<char>; _Tp = std::shared_ptr<User>; _Compare = std::less<std::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::basic_string<char>, std::shared_ptr<User> > >]
operator=(initializer_list<value_type> __l)
^
/usr/include/c++/4.8/bits/stl_map.h:300:7: note: no known conversion for argument 1 from ‘User*’ to ‘std::initializer_list<std::pair<const std::basic_string<char>, std::shared_ptr<User> > >’
Is the smart pointer wrongly declared?
Dict is std::map and you are trying to assign a pointer to a User to it which is wrong.
What you need is
dict["Adams"] = std::make_shared<User>("Adams", 666);