3

I used to have a normal member variable, which was initialized in the constructors as following:

ResourceSaveFunctions[OBJECTS_IDENT] = NULL; ResourceSaveFunctions[SPRITES_IDENT] = &GMProject::SaveSprite; ResourceSaveFunctions[SOUNDS_IDENT] = &GMProject::SaveSound; ResourceSaveFunctions[BACKGROUNDS_IDENT] = &GMProject::SaveBackground; ResourceSaveFunctions[PATHS_IDENT] = NULL; ResourceSaveFunctions[SCRIPTS_IDENT] = NULL; ResourceSaveFunctions[FONTS_IDENT] = NULL; ResourceSaveFunctions[TIMELINES_IDENT] = NULL; ResourceSaveFunctions[ROOMS_IDENT] = NULL; ResourceSaveFunctions["extension"] = &GMProject::SaveExtension; ResourceSaveFunctions[INCLUDES_IDENT] = NULL; ResourceSaveFunctions[TRIGGERS_IDENT] = NULL; 

The variable is a map with as key strings, and as data member-function-pointers. This worked perfectly fine. However as said I believe this map should be static (?) - the reason for the map is just to identify what the program should do during reading of a file. - NULL meaning "do nothing special".

So I changed it to the following:

std::map<std::string, GMProject::GMProjectMemFn> GMProject::ResourceSaveFunctions_INIT() { std::map<std::string, GMProjectMemFn> tmp; tmp.insert(std::make_pair(OBJECTS_IDENT,NULL)); tmp.insert(std::make_pair(SPRITES_IDENT, &GMProject::SaveSprite)); tmp.insert(std::make_pair(SOUNDS_IDENT, &GMProject::SaveSound)); tmp.insert(std::make_pair(BACKGROUNDS_IDENT, &GMProject::SaveBackground)); tmp.insert(std::make_pair(PATHS_IDENT, NULL)); tmp.insert(std::make_pair(SCRIPTS_IDENT, NULL)); tmp.insert(std::make_pair(FONTS_IDENT, NULL)); tmp.insert(std::make_pair(TIMELINES_IDENT, NULL)); tmp.insert(std::make_pair(ROOMS_IDENT, NULL)); tmp.insert(std::make_pair("extension", &GMProject::SaveExtension)); tmp.insert(std::make_pair(INCLUDES_IDENT, NULL)); tmp.insert(std::make_pair(TRIGGERS_IDENT, NULL)); return tmp; } const std::map<std::string, GMProject::GMProjectMemFn> GMProject::ResourceSaveFunctions(GMProject::ResourceSaveFunctions_INIT()); 

Where those things are declared in the header:

static const std::map<std::string, GMProjectMemFn> ResourceSaveFunctions; static std::map<std::string, GMProjectMemFn> ResourceSaveFunctions_INIT(); 

Now compiling suddenly brings up a lot of errors.

1>c:\program files\microsoft visual studio 10.0\vc\include\utility(163): error C2440: 'initializing' : cannot convert from 'int' to 'GMProject::GMProjectMemFn '

Which is about the conversion of NULL. However shouldn't this be just possible? Why is this not possible (yet in the previous method it was)? Should I use an explicit cast here?

EDIT: GMProjectMemFn defined as following:

typedef void (GMProject::*GMProjectMemFn)(const pTree&) const; 

pTree being a container.

4
  • What is the definition of GMProjectMemFn? Commented Nov 24, 2011 at 17:21
  • Are you implementing virtual tables yourself? I am not clear on what your big map o' member function pointers is needed for...it looks like something from a C program. Commented Nov 24, 2011 at 17:25
  • @Kerrek_SB "partially" - using visual studio 2010 - but no I can't use initializer lists. Commented Nov 24, 2011 at 17:26
  • @JohnZwinck Well this is used for something like "xml files" - during saving normally a standard approach can be used - which consists of reading the xml value, which contains a file location and then copying that file. However as I don't have control over the format of the xml files, in some specific cases something extra should occur. For these cases I wrote a seperate function. Commented Nov 24, 2011 at 17:30

2 Answers 2

1

std::make_pair creates a pair<T1, T2> where the types T1 and T2 are deduced implicitly from the types of the arguments. NULL expands to 0 (or 0L) so in your case make_pair returns a pair<string, int> (or a pair<string, long>).

You then try passing that pair<string, int> to map<string, GMProject::GMProjectMemFn>::insert() but this expects a pair<string, GMProjectMemFn>.

std::pair has a general copy constructor which will attempt implicit conversion of each member of the pair:

template <class U, class V> pair (const pair<U,V> &p) : first(p.first), second(p.second) { } 

but in your case this requires converting a const int& to a pointer, which is not permitted.

In your original case you were directly converting NULL into a pointer, which is well defined.

Explicitly typing your pair should fix this:

tmp.insert(std::pair<std::string, GMProject::GMProjectMemFn>(TIMELINES_IDENT, NULL)); 
Sign up to request clarification or add additional context in comments.

2 Comments

But doesn't std::pair have a non-explicit generalized copy constructor taking an arbitrarily typed std::pair and doing member-wise conversion? So a pair<string,int> should indeed be convertible to a pair<string,GMProjectMemFn> as long as int is convertible to GMProjectMemFn.
Yes, you're completely right. The real problem is that a int const& can't be implicitly cast to a pointer. I'll correct my answer. Thanks for pointing that out!
0

ah. NULL is probably defined only as literal 0, make_pair deduces this to integer, and pair<int,int> is not convertible to pair<int,GMProjectMemFn>. It worked with assignment through operator[] because (I guess) of implicit conversion from 0 to GMProjectMemFn.

So, try writing make_pair(PATHS_IDENT, (GMProjectMemFn)0).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.