9

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
  • 3
    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 Commented Aug 22, 2017 at 11:52
  • 1
    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 Commented Aug 22, 2017 at 11:59

2 Answers 2

14

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.

Sign up to request clarification or add additional context in comments.

2 Comments

There's a good reason for this distinction, I think. E.g. one would expect &m to be of type std::map<int, STATEFUNC> *, so a different syntax is needed, specifically &X::m to get a std::map<int, STATEFUNC> X::*. It is then consistent to require the latter syntax also for non-static methods, even if the syntax with unqualified-id is illegal.
@ArneVogel - You are very much correct. Furthermore, one need not even make a distinction between member functions and data members when defining pointers to members. If we have T C::* pm = &C::m;, then the declaration is correct whether T is an object type (which m matches) or a function alias like using T = void(void); (and m is a member function with this prototype). The syntax is very consistent this way, despite the verbosity.
9

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.