C++ - Vector of function pointers inside class - c++

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); });

Related

Can not convert typedef to std::pair in Visual Studio 2015

I try to upgrade some projects from Visual Studio 2010 to 2015. In 2010 everything works fine, but in 2015 I get compiler errors which I don't really understand.
I condensed the code into an SSCCE
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <string>
#include <sstream>
#define UNUSED(x) (void(x))
class ColumnDef
{
public:
};
class XMLColumnDef
{
public:
typedef std::pair<std::string, XMLColumnDef> pair;
typedef std::pair<std::string, XMLColumnDef *> ptr_pair;
public:
// Move constructor for moving the column into an container
// without destroying it. Note that the source is no longer valid after
// such a move.
XMLColumnDef(XMLColumnDef &oSource)
{
mColumn = oSource.mColumn;
oSource.mColumn = NULL;
}
XMLColumnDef(ColumnDef *pColumn)
{
mColumn = pColumn;
}
virtual ~XMLColumnDef(void)
{
delete mColumn;
}
private:
ColumnDef *mColumn;
};
class XMLNodeObserver
{
public:
typedef std::map<std::string, XMLNodeObserver *> map;
typedef std::pair<std::string, XMLNodeObserver *> pair;
typedef std::map<std::string, XMLColumnDef> row_def;
public:
XMLNodeObserver(void) {}
virtual ~XMLNodeObserver(void) {};
void addObserver(XMLNodeObserver::map &oNodeObserver, std::string const &oPath, XMLNodeObserver *oObserver = NULL)
{
UNUSED(oNodeObserver);
UNUSED(oPath);
UNUSED(oObserver);
}
void addColumnDef(XMLNodeObserver::map &oNodeObserver, std::string const &oPath, ColumnDef *oColumn, XMLNodeObserver *oObserver = NULL)
{
if (oObserver == NULL)
oObserver = this;
addObserver(oNodeObserver, oPath, oObserver);
XMLColumnDef::pair pr = std::make_pair(oPath, XMLColumnDef(oColumn));
if (oObserver->mColumnDefs.find(oPath) != oObserver->mColumnDefs.end())
{
// If a node already exists, we report an internal error, because this indicates a program bug and should be fixed.
std::cerr << "INTERNAL ERROR: Duplicate rowdef key in XML node observer: " << oPath << std::endl;
}
oObserver->mColumnDefs.insert(pr);
}
private:
row_def mColumnDefs;
bool mDebugMode;
};
int main()
{
XMLNodeObserver o;
XMLNodeObserver::map om;
o.addColumnDef(om, "/testpath", new ColumnDef());
std::cout << "\nDone! Press any key..." << std::endl;
std::cin.ignore();
return 0;
}
The error I get in this line:
oObserver->mColumnDefs.insert(pr);
The error I get is this:
junk.cpp(104): error C2664: 'void std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::insert(std::initializer_list<std::pair<const _Kty,_Ty>>)': cannot convert argument 1 from 'XMLColumnDef::pair' to 'std::pair<const _Kty,_Ty> &&'
with
[
_Kty=std::string,
_Ty=XMLColumnDef,
_Pr=std::less<std::string>,
_Alloc=std::allocator<std::pair<const std::string,XMLColumnDef>>
]
and
[
_Kty=std::string,
_Ty=XMLColumnDef
]
junk.cpp(104): note: Reason: cannot convert from 'XMLColumnDef::pair' to 'std::pair<const _Kty,_Ty>'
with
[
_Kty=std::string,
_Ty=XMLColumnDef
]
junk.cpp(104): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
It looks as if Visual Studio 2015 doesn't like it that the parameter oPath is const & but that shouldn't matter as it should be assigned to the pair member.
I also removed the typedefs and tried to compile it with the long names, but that doesn't seem to be the problem (and shouldn't anyway) because I get the same error.
Like:
std::pair<std::string, XMLColumnDef> pr = std::pair<std::string, XMLColumnDef>(oPath, XMLColumnDef(oColumn));
Pairs in maps are of type pair<const key,value> and not pair<key,value>. Try using the MyMapType::value_type typedef instead. You get it for free!
example:
typedef std::map<std::string, XMLNodeObserver *> MyMapType;
typedef MyMapType::value_type MyPairType;

Error while adding shared pointer to the vector

abstract base class:
#ifndef BUILDINGORG_H
#define BUILDINGORG_H
#include <iostream>
#include <memory>
#include <vector>
class BuildingOrg
{
public:
BuildingOrg(int _id);
virtual int addBuildingComponent(std::shared_ptr<BuildingOrg> buildingOrg,
std::string _type) const;
virtual void removeBuildingComponent(std::shared_ptr<BuildingOrg> buildingOrg);
virtual void getInfo()=0;
private:
int id;
std::string type;
};
#endif // BUILDINGORG_H
concrete subclass:
#ifndef BUILDINGCOMPONENT_H
#define BUILDINGCOMPONENT_H
#include "buildingorg.h"
class BuildingComponent : public BuildingOrg
{
public:
BuildingComponent(int _id);
int addBuildingComponent(std::shared_ptr<BuildingOrg> _buildingOrg,
std::string _type) const override;
void removeBuildingComponent(std::shared_ptr<BuildingOrg> buildingOrg)
override;
void getInfo() override;
private:
std::vector<std::shared_ptr<BuildingOrg>> building_Org;
};
#endif // BUILDINGCOMPONENT_H
Implementation of subclass:
#include "buildingcomponent.h"
BuildingComponent::BuildingComponent(int _id):
BuildingOrg(_id)
{
}
int BuildingComponent::addBuildingComponent(std::shared_ptr<BuildingOrg> _buildingOrg, std::string _type) const
{
building_Org.push_back(_buildingOrg);// I am having error here
return 1;
}
void BuildingComponent::removeBuildingComponent(std::shared_ptr<BuildingOrg> buildingOrg)
{
}
void BuildingComponent::getInfo()
{
}
When I try to put shared pointer in my Vector I get this nasty error;
I really don't know why I am getting the error:
cpp:10: error: passing 'const std::vector<std::shared_ptr<BuildingOrg> >' as 'this' argument of 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::shared_ptr<BuildingOrg>; _Alloc = std::allocator<std::shared_ptr<BuildingOrg> >; std::vector<_Tp, _Alloc>::value_type = std::shared_ptr<BuildingOrg>]' discards qualifiers [-fpermissive]
building_Org.push_back(_buildingOrg);
I don’t understand what is it saying.
The const in int addBuildingComponent(std::shared_ptr<BuildingOrg> _buildingOrg, std::string _type) const override; is a promise that addBuildingComponent will not change BuildingComponent. However, it tries to modify the member variable building_Org with the push_back()...
Removing the const from addBuildingComponent() should fix the error.
The discards qualifiers part of the error message refers to the conflict with the const qualifier of the member function.
C++ template related error messages can be notoriously difficult to parse at first, but it does get easier with practice :-)
You defined BuildingComponent::addBuildingComponent method as const (i.e. that it won't change member varialbles), but you are adding passed in value to a member list (i.e. changing the member variable).
addBuildingComponent() is a const method. within its scope, *this is const, and so this->building_Org is const.
std::vector::push_back() is a non-const method. So it can't be called in a context where the vector is const.

Returning a map of structs from within a class (where the struct definition is within the class): compile error

I have a class, and within that class I define a struct. The struct has overloaded comparison operators so that it can be used with a map (with an int as the key).
Prior to messing with classes, I had the struct defined in a .cc file, and that file also contained a function which returned a map of this struct. It worked.
Now I want to have the struct defined in the class header, and the class should have a function which returns a map of structs.
Here is a simplified version of my code, which compiles with the same error as the full version. I don't understand the error, and would appreciate any help!
Cheers.
myclass.h:
#include <map>
class myclass {
public:
struct mystruct {
int i;
mystruct();
mystruct(int j);
bool operator==(const mystruct& rhs);
bool operator>(const mystruct& rhs);
bool operator<(const mystruct& rhs);
};
::std::map<int,mystruct> getStructMap();
};
myclass.cc:
#include <map>
#include "myclass.h"
myclass::mystruct::mystruct(int j) : i(j) {};
myclass::mystruct::mystruct() : i(-1) {};
bool ::myclass::mystruct::operator==(const ::myclass::mystruct& rhs) {return i==rhs.i; }
bool ::myclass::mystruct::operator>(const ::myclass::mystruct& rhs) {return i>rhs.i; }
bool ::myclass::mystruct::operator<(const ::myclass::mystruct& rhs) {return i<rhs.i; }
::std::map<int,::myclass::mystruct> ::myclass::getStructMap() {
::std::map<int,::myclass::mystruct> structMap;
for (int i=0;i<5;i++) structMap[i]=::myclass::mystruct(i);
return structMap;
}
myprogram.cc:
#include <iostream>
#include <map>
#include "myclass.h"
int main() {
myclass myobj;
::std::map<int,::myclass::mystruct> mymap;
mymap=myobj.getStructMap();
}
compile error:
> g++ -o myprogram myprogram.cc myclass.cc
myclass.cc:12: error: ‘class std::map<int, myclass::mystruct, std::less<int>,std::allocator<std::pair<const int, myclass::mystruct> > >::myclass’ has not been declared
myclass.cc:12: error: ISO C++ forbids declaration of ‘getStructMap’ with no type
myclass.cc: In function ‘int getStructMap()’:
myclass.cc:15: error: cannot convert ‘std::map<int, myclass::mystruct, std::less<int>, std::allocator<std::pair<const int, myclass::mystruct> > >’ to ‘int’ in return
Currently your code in parsed as
/*missing type*/ ::std::map<int,::myclass::mystruct>::myclass::getStructMap()
Thus, first error, map doesn't have myclass member (or subclasses, method, typedef, ...)
then the second error : no return type (so assuming int and thus the conversion error).
So to solve that, in myclass.cc, you may remove extra :: as follow:
::std::map<int,::myclass::mystruct> myclass::getStructMap() {
or add extra parenthesis:
::std::map<int,::myclass::mystruct> (::myclass::getStructMap()) {

std::map with lambda comparator

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.

C++ error: no viable conversion from 'mapped_type' to 'int'

I am trying to implement the a map from the C++ STL as follows:
#include <string>
#include <iostream>
#include <map>
using namespace std;
#include "assembler.h"
// This Class makes use of the Map Template from the Standart Template Library
// All addresses are stored as numerical (Dec) integers
SymbolTable::SymbolTable() { // Constructor
map <string, int> symbolTable;
int address = 0;
}
void SymbolTable::addEntry(string symbol, int address) {
symbolTable[symbol] = address;
address++;
}
// Returns true if symbolTable already contains symbol
bool SymbolTable::contains(string symbol) {
if (symbolTable.find(symbol) == symbolTable.end()) { return true; }
else { return false; }
}
int SymbolTable::getAddress(string symbol) {
return symbolTable[symbol];
}
I try to compile this with
c++ *.cpp -0 assembler.out
and I get the following error message:
symboltable.cpp:57:9: error: no viable conversion from 'mapped_type' (aka 'std::basic_string<char>') to 'int'
return symbolTable[symbol];
^~~~~~~~~~~~~~~~~~~
1 error generated.
I have searched for this error online and all I get is bug reports relating to the STL and I cannot figure out if those reports are the same problem I am having and if so how to get around it. Am I doing something wrong?
I have tried (probably stupidly) to typecast the offending line as
return (int) symbolTable[symbol];
Thank you for any help.
My header file declares the class as:
class SymbolTable {
public:
SymbolTable();
void addEntry(string, int);
bool contains(string);
int getAddress(string);
private:
map <string, string> symbolTable;
int address;
};
This:
SymbolTable::SymbolTable() { // Constructor
map <string, int> symbolTable;
^
^
is a function-local variable, not a member variable. It is not the same as the symbolTable that you're accessing in e.g. getAddress, which presumably is a member variable. You haven't shown the class body, but my guess is that it's defined differently.