9
votes

Trying to create a map of int to member function pointer and initialize it inside a constructor initializer. Like this:

class X
{
    using STATEFUNC = void(X::*)(int);
public:
    X() : m{ { 1, &setState1 } } {}

    void setState1(int x) { cout << "state1" << endl; }

    void setState2(int x) { cout << "state2" << endl; }


    std::map<int, STATEFUNC> m;
};

I would say this is correct, but Visual studio 2017 says:

Error C2664 'std::map,std::allocator>>::map(std::initializer_list>)': cannot convert argument 1 from 'initializer list' to 'std::initializer_list>'

Error C2276 '&': illegal operation on bound member function expression

When you remove the address of operator from the member function the first error message stays the same but the second changes to:

Error C3867 'X::setState1': non-standard syntax; use '&' to create a pointer to member

How do you initialize a map of int to member function pointer inside a constructor initializer list?

2
Interesting. Not sure why but it requires the class name here. Hopefully someone will know why X() : m{ { 1, &X::setState1 } } {} works but X() : m{ { 1, &setState1 } } {} doesn't - NathanOliver
identifier can never be used to take the address of a member function (either explicitly with & or by decay); you always have to use a qualified-id - M.M

2 Answers

9
votes

Try with

X() : m{ { 1, &X::setState1 } } {}

Using only &setState1 I get, from g++, the following message error

error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say ‘&X::setState1’ [-fpermissive]

From clang++ the error is simply

error: must explicitly qualify name of member function when taking its address

-- EDIT --

My answer explain how to solve the problem.

To understand why &X::setState1 works and &setState1 doesn't, please see the StoryTeller's answer (+1)

14
votes

The answer by max66 is the fix. As for why it's the fix: the reason is that your code does not create a pointer to a member. To quote n4659 (last C++17 draft, but previous standard revisions say the same):

[expr.unary.op/4]

A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses. [ Note: That is, the expression &(qualified-id), where the qualified-id is enclosed in parentheses, does not form an expression of type “pointer to member”. Neither does qualified-id, because there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to member function” as there is from an lvalue of function type to the type “pointer to function” ([conv.func]). Nor is &unqualified-id a pointer to member, even within the scope of the unqualified-id's class.  — end note ]

X::setState1 is a qualified id, but setState1 is not.