std::map with lambda comparator - c++

My below code is giving me compiler error and I an not understanding what wrong I am doing. Can anyone help please?
Basically all I am trying to do is pass a STL map container by reference to a function which would fill it up. This map container also has a comparator lambda associated with it.
#include "stdafx.h"
#include <functional>
#include <map>
using namespace std;
typedef struct _tagAddressBook
{
string strFirstName;
string strLastName;
long nZipCode;
} AddressBook;
void foo(map<string, AddressBook, function<bool(const string&, const string&)>> &myAddressBook)
{
AddressBook addressBookInstance;
addressBookInstance.strFirstName = "Bob";
addressBookInstance.strLastName = "Parker";
addressBookInstance.nZipCode = 12345;
myAddressBook.insert(std::pair<string, AddressBook>(addressBookInstance.strFirstName, addressBookInstance));
}
int _tmain(int argc, _TCHAR* argv[])
{
auto myComparator = [] (const string &strLeft, const string &strRight) { return(strLeft.compare(strRight) <= 0 ? true : false); };
map<string, AddressBook, decltype(myComparator)> myAddressBook(myComparator);
foo(myAddressBook);
return 0;
}
I get the below compilation error on VS2012
Error 1 error C2664: 'foo' : cannot convert parameter 1 from 'std::map<_Kty,_Ty,_Pr>' to 'std::map<_Kty,_Ty,_Pr> &' d:\my projects\mapwithlambdacomparator\mapwithlambdacomparator\mapwithlambdacomparator.cpp 32
2 IntelliSense: a reference of type "std::map<std::string, AddressBook, std::function<bool (const std::string &, const std::string &)>, std::allocator<std::pair<const std::string, AddressBook>>> &" (not const-qualified) cannot be initialized with a value of type "std::map<std::string, AddressBook, lambda []bool (const std::string &strLeft, const std::string &strRight)->bool, std::allocator<std::pair<const std::string, AddressBook>>>" d:\My Projects\MapWithLambdaComparator\MapWithLambdaComparator\MapWithLambdaComparator.cpp 32

Lambda functions are not related to std::function. In fact, each is its own class type. If you want to do what it appears you do, you can do it by template through foo and let deduction sort it out.
template <typename Cmp>
void foo(map<std::string, AddressBook, Cmp> &myAddressBook)
{
AddressBook addressBookInstance;
addressBookInstance.strFirstName = "Bob";
addressBookInstance.strLastName = "Parker";
addressBookInstance.nZipCode = 12345;
myAddressBook.insert(std::pair<string, AddressBook>(addressBookInstance.strFirstName, addressBookInstance));
}
This works on my toolchain, "Apple LLVM version 5.0 (clang-500.2.75) (based on LLVM 3.3svn)". I see no reason it would not work with your toolchain as well.

Please make an alias:
using AdressBookMap = map<string, AddressBook, function<bool(const string&, const string&)>>;
Then use it:
void foo(AddressBookMap& myAddressBook)
{
// ...
}
int main(int argc, char* argv[])
{
auto myComparator = [] (...) { ... };
AddressBookMap myAddressBook(myComparator);
foo(myAddressBook);
return 0;
}
As Whoz said, lambdas are not std::function; the latter can be implicitly constructed from the former, but they don't have the same type. This means a std::map parametrized by one is completely unrelated to a std::map parametrized by the other.

Related

Can't deserialise from Json using nlohman json using custom class with private members

Really struggling to do this; it should be really simple, but I can't work out how. I've got it working for struct, but not for a class with private members. Following instructions from (https://github.com/nlohmann/json). I'm building this on Visual Studio 2019 and obtained the library from nuget, version 3.10.4.
The error is on the get line in main.cpp, where it says "no matching overloaded function call found.". There are two other errors listed;
Error (active) E0304 no instance of overloaded function
"nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType,
NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType,
JSONSerializer, BinaryType>::get [with ObjectType=std::map,
ArrayType=std::vector, StringType=std::string, BooleanType=bool,
NumberIntegerType=int64_t, NumberUnsignedType=uint64_t,
NumberFloatType=double, AllocatorType=std::allocator,
JSONSerializer=nlohmann::adl_serializer,
BinaryType=std::vector<uint8_t, std::allocator<uint8_t>>]" matches the
argument
list Assignment4 C:\Users\allsoppj\source\repos\Assignment4\Assignment4\main.cpp 120
object type is: json
Error C2672 'nlohmann::basic_jsonstd::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer,std::vector<uint8_t,std::allocator<uint8_t>>::get':
no matching overloaded function
found Assignment4 C:\Users\allsoppj\source\repos\Assignment4\Assignment4\main.cpp 120
Error C2893 Failed to specialize function template 'unknown-type
nlohmann::basic_jsonstd::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer,std::vector<uint8_t,std::allocator<uint8_t>>::get(void)
noexcept()
const' Assignment4 C:\Users\allsoppj\source\repos\Assignment4\Assignment4\main.cpp 120
Here's my address1.h
#include <nlohmann/json.hpp>
#include <string>
using json = nlohmann::json;
class address1 {
private:
std::string street;
int housenumber;
int postcode;
public:
address1(std::string street, int housenumber, int postcode);
NLOHMANN_DEFINE_TYPE_INTRUSIVE(address1, street, housenumber, postcode);
};
address1.cpp
#include "address1.h"
address1::address1(std::string street, int housenumber, int postcode) :street(street), housenumber(housenumber), postcode(postcode) {}
main.cpp
int main(int argc, const char** argv) {
address1 p1 = { "home",2,3 };
json j = p1;
auto p3 = j.get<address1>();
std::cout << std::setw(2) << j << std::endl;
}
The problem is that your address1 type does not have a default constructor. From https://nlohmann.github.io/json/features/arbitrary_types/#basic-usage :
When using get<your_type>(), your_type MUST be DefaultConstructible.
(There is a way to bypass this requirement described later.)
If I add address1() = default; to your example, then it compiles no problem.
Ps. The "bypass described later" can be found here: https://nlohmann.github.io/json/features/arbitrary_types/#how-can-i-use-get-for-non-default-constructiblenon-copyable-types

C++ - Vector of function pointers inside class

I am making my own programming language. I made classes (like 'string' or 'int) that derive from the object class. I am making standard types like string and int so I have a base I can work off (expand my language with itself if that makes sense). Each standard type has a unordered_map of functions. I would love to hear a way to fix this/another approach.
When I run the program, I get this error that I don't understand:
C2664: 'std::pair<const _Kty,_Ty>::pair(std::pair<const _Kty,_Ty> &&)': cannot convert argument 2 from '_Ty' to 'const _Ty2 &'
It's referring to line 62. Where the error comes from:
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\xmemory0 line:881
The code from xmemory0:
template<class _Objty,
class... _Types>
static void construct(_Alloc&, _Objty * const _Ptr, _Types&&... _Args)
{ // construct _Objty(_Types...) at _Ptr
::new (const_cast<void *>(static_cast<const volatile void *>(_Ptr)))
_Objty(_STD forward<_Types>(_Args)...);
}
My code:
#include <iostream>
#include <unordered_map>
#include <string>
#include <functional>
struct Object;
typedef std::unordered_map<std::string, std::function<Object*(std::string*)>> stdtypefunc_map;
struct Object
{
};
struct StdType : public Object
{
stdtypefunc_map functions;
};
struct stringtype : public StdType
{
stringtype()
{
functions.emplace("GetValue", &stringtype::GetValue);
}
Object* GetValue(std::string args[])
{
std::cout << "GetValue()" << std::endl;
}
};
int main()
{
stringtype s;
return 0;
}
In your code, line 62 is this statement:
functions.emplace("GetValue", &stringtype::GetValue);
functions is an std::unordered_map whose key_type is std::string and mapped_type is std::function<Object*(std::string*)>.
emplace() constructs a new std::unordered_map::value_type in the map, passing the values you specify to the value_type's constructor. In this case, that value_type is a std::pair<const std::string, std::function<Object*(std::string*)>>, and you are passing in 2 values to constructor the std::pair with.
The error message you are seeing is basically saying that the compiler can't convert &stringtype::GetValue to std::function<Object*(std::string*)>. For example, here is a simplified example that reproduces the same failure, and GCC gives a VERY DETAILED error message explaining why it failed (which is too large to post here, so I'll post only the relevant pieces):
https://ideone.com/qVLkQd
#include <iostream>
#include <unordered_map>
#include <string>
#include <functional>
struct Object;
typedef std::unordered_map<std::string, std::function<Object*(std::string*)>> stdtypefunc_map;
struct Object
{
};
struct StdType : public Object
{
stdtypefunc_map functions;
};
struct stringtype : public StdType
{
stringtype()
{
functions.emplace("GetValue", &stringtype::GetValue);
}
Object* GetValue(std::string args[])
{
std::cout << "GetValue()" << std::endl;
}
};
int main()
{
stringtype s;
return 0;
}
/usr/include/c++/6/ext/new_allocator.h:120:4: error: no matching function for call to ‘std::pair<const std::__cxx11::basic_string<char>, std::function<Object*(std::__cxx11::basic_string<char>*)> >::pair(const char [9], Object* (stringtype::*)(std::__cxx11::basic_string<char>*))’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
/usr/include/c++/6/ext/new_allocator.h:120:4: note: cannot convert ‘std::forward<Object* (stringtype::*)(std::__cxx11::basic_string<char>*)>((* & __args#1))’ (type ‘Object* (stringtype::*)(std::__cxx11::basic_string<char>*)’) to type ‘const std::function<Object*(std::__cxx11::basic_string<char>*)>&’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
Which makes sense. You can't store a pointer-to-member-method for a non-static method into a std::function unless you take into account that it will need an object instance to call the method on. Such as by using std::bind() to bind an object instance with the pointer-to-member-method:
using std::placeholders::_1;
functions.emplace("GetValue", std::bind(&stringtype::GetValue, this, _1));
Or, by using a lambda to capture the object:
functions.emplace("GetValue", [this](std::string *args){ return this->GetValue(args); });

Why passing char* to a string argument generates a compilation error? [duplicate]

This question already has answers here:
Pass a string in C++
(8 answers)
Closed 5 years ago.
I was prototyping with the following code.
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
template<class container, class value> class Add {
public:
Add(){};
~Add(){};
void add_value(container& cont, value& val){
std::for_each(cont.begin(), cont.end(), [&val](value& v){v +=val;});
};
};
int main(int argc, char const *argv[])
{
Add<std::vector<std::string>, std::string> a;
std::vector<std::string> vec = {"a", "b", "c", "d"};
std::string foo= "1";
a.add_value(vec, foo); // compiles fine
a.add_value(vec, "1"); // generates an error
return 0;
}
and i got the following error
template.cpp:28:25: error: invalid initialization of non-const reference of type ‘std::__cxx11::basic_string<char>&’ from an rvalue of type ‘std::__cxx11::basic_string<char>’
Why it's not possible to pass a char* to a string argument ?
As far as i know an implicit conversion will be executed in order to convert the char* to std::string and the result will be passed to the function.
You defined the add_value as following:
void add_value(container& cont, value& val)
Where the string is a non-const reference, the compiler expect this reference to point to a modifiable variable somewhere else.
However, when you pass a const char[], even if this type could be converted to a string (in case it would compile), it is done on the fly and the string is not modifiable. Actually, the char* is not modifiable neither. That is why your code do not compile.
You may define your function as following and it would work:
void add_value(container& cont, const value& val)

How to put const string value in map

I want to create a map ,
std::map <MESSAGE_CATEGORY, const std::string> m_mapResponseDesc;
I am using operator[] to append a value in the map:
m_mapResponseDesc[STATUS_LIMIT] = "Limit has been exceeded";
STATUS_LIMIT is of type enum.
I am getting error:
error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::basic_string<_Elem,_Traits,_Ax>' (or there is no acceptable conversion)
Please point out what mistake I have done. I am not getting any clue.
Since operator[] returns a reference (to a const std::string) you will need to use the insert() method instead.
#include <map>
#include <string>
using namespace std;
int main()
{
std::map<int, const std::string> m;
m.insert(std::make_pair(1, "Hello"));
return 0;
}
Update for C++11:
You can do this even easier now:
std::map<int, const std::string> status = {
{200, "OK"},
{404, "Not Found"}
};

Comparing an error code enum with std::error_code

I'm using the C++11 system_error error code library to create a custom error class for a library I'm making. I've done this before with boost::error_code, but I can't quite it get it working with std::error_code. I'm using GCC 4.6.
Basically, I've laid out all the boilerplate code to create an error class, an error_category, and the conversion routines in the STD namespace to convert my custom enums into an std::error_code object:
namespace mylib
{
namespace errc {
enum my_error
{
failed = 0
};
inline const char* error_message(int c)
{
static const char* err_msg[] =
{
"Failed",
};
assert(c < sizeof(err_msg) / sizeof(err_msg[0]));
return err_msg[c];
}
class my_error_category : public std::error_category
{
public:
my_error_category()
{ }
std::string message(int c) const
{
return error_message(c);
}
const char* name() const { return "My Error Category"; }
const static error_category& get()
{
const static my_error_category category_const;
return category_const;
}
};
} // end namespace errc
} // end namespace mylib
namespace std {
inline error_code make_error_code(mylib::errc::my_error e)
{
return error_code(static_cast<int>(e), mylib::errc::my_error_category::get());
}
template<>
struct is_error_code_enum<mylib::errc::my_error>
: std::true_type
{ };
The problem is, implicit conversion between my error code enums and std::error_code objects doesn't seem to be working, so I can't for example try and compare an instance of std::error_code with enum literals:
int main()
{
std::error_code ec1 = std::make_error_code(mylib::errc::failed); // works
std::error_code ec2 = mylib::errc::failed; // doesn't compile
bool result = (ec2 == mylib::errc::failed); // doesn't compile
}
The expression ec2 == mylib::errc::failed won't compile - I have to say ec2 == std::make_error_code(mylib::errc::failed).
The error the compiler emits is:
In file included from test6.cc:3:0:
/usr/include/c++/4.6/system_error: In constructor ‘std::error_code::error_code(_ErrorCodeEnum, typename std::enable_if<std::is_error_code_enum<_ErrorCodeEnum>::value>::type*) [with _ErrorCodeEnum = mylib::errc::my_error, typename std::enable_if<std::is_error_code_enum<_ErrorCodeEnum>::value>::type = void]’:
test6.cc:70:37: instantiated from here
/usr/include/c++/4.6/system_error:127:9: error: cannot convert ‘mylib::errc::my_error’ to ‘std::errc’ for argument ‘1’ to ‘std::error_code std::make_error_code(std::errc)’
And here's an Ideone link.
So, why isn't this working? Do I need additional boilerplate code to enable mylib::errc::my_error enums to be implicitly convertible to std::error_code? I thought that the specialization of std::make_error_code takes care of that?
You have to move error_code make_error_code(mylib::errc::my_error e) function from std to your error namespace (mylib::errc). Please check http://ideone.com/eSfee.