2017-08-22 7 views
9

Création d'une mappe d'int sur un pointeur de fonction membre et initialisation dans un initialiseur de constructeur. Comme ceci:Utilisation de la liste d'initialiseurs de la carte dans l'initialiseur de constructeur

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

je dirais que cela est vrai, mais Visual Studio 2017 dit:

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

Lorsque vous supprimez l'adresse de l'opérateur de la fonction de membre du premier message d'erreur reste le même, mais le deuxième changement à:

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

Comment initialize-vous une carte de int pointeur de fonction membre dans une liste d'initialisation du constructeur?

+3

Intéressant. Je ne sais pas pourquoi mais cela nécessite le nom de la classe ici. Espérons que quelqu'un saura pourquoi 'X(): m {{1, & X :: setState1}} {}' fonctionne mais 'X(): m {{1, & setState1}} {}' ne peut pas – NathanOliver

+1

'identifier' ne jamais être utilisé pour prendre l'adresse d'une fonction membre (soit explicitement avec '&' ou par décroissance); vous devez toujours utiliser un identifiant qualifié –

Répondre

9

Essayez avec

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

En utilisant seulement &setState1 que je reçois, de g ++, l'erreur de message suivant

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]

De clang ++ l'erreur est tout simplement

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

- EDIT -

Ma réponse explique comment résoudre le problème.

Pour comprendre pourquoi &X::setState1 œuvres et &setState1 n'a pas, s'il vous plaît voir

14

réponse du StoryTeller (1) Le answer par max66 est le correctif. Quant à savoir pourquoi c'est le correctif: la raison en est que votre code ne crée pas de pointeur vers un membre. Pour citer n4659 (dernière 17 C++ projet, mais les révisions standard précédentes disent la même):

[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 est un identifiant qualifié, mais setState1 n'est pas.

+0

Il y a une bonne raison pour cette distinction, je pense. Par exemple. on s'attendrait à ce que '' & m'' soit de type '' std :: map * '', donc une syntaxe différente est nécessaire, spécifiquement '' & X :: m'' pour obtenir un '' std: : map X :: * ''. Il est alors cohérent d'exiger cette dernière syntaxe également pour les méthodes non statiques, même si la syntaxe avec un id non qualifié est illégale. –

+0

@ArneVogel - Vous avez raison. De plus, il n'est même pas nécessaire de faire une distinction entre les fonctions membres et les membres de données lors de la définition des pointeurs vers les membres. Si nous avons 'TC :: * pm = &C::m;', alors la déclaration est correcte si 'T' est un type d'objet (lequel m correspond) ou un alias de fonction comme' using T = void (void); '(et m est une fonction membre avec ce prototype). La syntaxe est * très cohérente * de cette façon, malgré la verbosité. – StoryTeller