-1

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;
}
roguemacro
  • 199
  • 2
  • 16
  • 4
    You should be able to (re)produce the issue with less code. – Jarod42 Jul 24 '19 at 23:01
  • 2
    "Where the error comes from: c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\xmemory0 line:881" I highly doubt the error it from the standard library with MSVC. It's got to be in yours somewhere. Please try to narrow it down. –  Jul 24 '19 at 23:24
  • 2
    What both comments above are asking for (I am pretty sure) is a [mcve]. – Yunnosch Jul 24 '19 at 23:44
  • I didn't mean that it is MSVC's fault. The error is mine, but that is where the error is pointing to. I just know it's mine because I tried commenting out this line `functions.emplace("GetValue", &stringtype::GetValue);` in stringtype. – roguemacro Jul 25 '19 at 09:01

1 Answers1

2

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); });
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I was thinking that if the user makes a string variable (in my language) he can access the functions by doing `stringvar.SomeFunc()`. Then c++ will look for "SomeFunc" in the function map of that stringtype instance. Since the variable is stored as a stringtype object. Should I use a lambda or bind() for this purpose? – roguemacro Jul 25 '19 at 09:09
  • @PhysicalExperience it is largely a matter of personal choice, but there are few situations where `bind()` is ever preferred over a lambda. See [Bind vs Lambda?](https://stackoverflow.com/questions/1930903/) and [Why use std::bind over lambdas in C++14?](https://stackoverflow.com/questions/17363003/). – Remy Lebeau Jul 25 '19 at 15:30