2017-05-18 6 views
2

Je suis aux prises avec l'erreur de compilation C2751 et je ne comprends pas vraiment ce qui le cause exactement. Le petit code suivant produit l'erreur:C++ Compiler Error C2751 - Qu'est-ce qui le cause exactement?

#include <iostream> 

class A { 
public: 
    A() { std::cout << "A constructed" << std::endl; }; 
    static A giveA() { return A(); } 
}; 

class B { 
public: 
    B (const A& a) { std::cout << "B constructed" << std::endl; } 
}; 


int main() { 

    B b1 = B (A::giveA()); // works 
    B b2 (B (A::giveA())); // C2751 
    B b3 (A::giveA()); // works 

} 

sortie du compilateur:

consoleapplication1.cpp(21): error C2751: 'A::giveA': the name of a function parameter cannot be qualified

Pourquoi ne puis-je appeler le constructeur explicitement b2?

+1

Quel compilateur utilisez-vous? Parce que gcc 5.4 construit avec du code sans aucun problème. – knst

+1

@knst il utilise MSVC (voir le lien C2751) – vaxquis

+1

@knst Il ne compile pas avec [clang] (https://wandbox.org/permlink/UajAZ5zfaV8QWmZD) non plus. – songyuanyao

Répondre

6

C'est le problème de la most vexing parse. Compiler sous clang donne un diagnostic complet:

<source>:18:17: error: parameter declarator cannot be qualified 
    B b2 (B (A::giveA())); // C2751 
      ~~~^ 

<source>:18:10: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse] 
    B b2 (B (A::giveA())); // C2751 
     ^~~~~~~~~~~~~~~~~ 

<source>:18:11: note: add a pair of parentheses to declare a variable 
    B b2 (B (A::giveA())); // C2751 
     ^
      (   ) 
1 warning and 1 error generated. 
Compiler exited with result code 1 

Faire que le compilateur suggère corrige ce problème:

B b2 ((B (A::giveA()))); // no error 
+0

Merci, la sortie clang était vraiment utile. Puis-je demander pourquoi est-il "permis" de déclarer une fonction dans une fonction? Je ne peux pas vraiment penser à une situation où je voudrais faire cela. – spinakker

+0

Imaginez comment vous pourriez écrire: "' b2' est une fonction qui prend une fonction qui retourne un 'B' et prend une fonction qui retourne un' A :: giveA' sans prendre d'arguments " –

2

Cette instruction particulière est ambiguë; De la façon dont vous l'avez indiqué, il peut s'agir d'une déclaration de fonction ou d'une définition de variable.

Utilisation de parenthèses supplémentaires devraient aider - il obtient sans ambiguïté puisque vous ne pouvez pas déclarer/appeler une fonction avec deux parenthèses:

B b1 = B(A::giveA()); // works 
B b2((B(A::giveA()))); // works for me 
B b3(A::giveA()); // works 

Voir aussi ici: https://en.wikipedia.org/wiki/Most_vexing_parse

+0

"Il n'y a pas de c-tor/méthode' B (B b) ', et le compilateur pense que vous l'appelez." Le compilateur _knows_ que vous ne pouvez pas déclarer un tel constructeur. Il ne pensera pas que vous l'appelez (sauf s'il a un bug). – cpplearner

+0

@cpplearner merci d'avoir repéré cela, corrigé. – vaxquis

2
B b2 (B (A::giveA())); 

Même si vous aviez un constructeur de copie de B classe, vous devriez toujours obtenir erreur car la ligne ci-dessus est conforme aux règles de grammaire d'une déclaration de fonction. Avoir des parenthèses autour de B(A::give()) résout votre problème.

2

Ah, le vieux problème du most vexing parse.

Cette ligne ici

B b2 (B (A::giveA())); // C2751 

est interprété en fonction b2 retour B et prendre un paramètre appelé A::giveA de type fonction B(). L'erreur C2751 est provoquée par le nom non valide A::giveA: vous ne pouvez pas utiliser un nom qualifié comme nom de paramètre.

Pour copier un objet B temporaire dans b2 (que je crois est votre intention) vous pouvez ajouter d'autres supports

B b2 ((B (A::giveA()))); 

ou utilisez des accolades (tant qu'il n'y a pas un constructeur qui accepte les listes contenant initialiseur un type convertible en type B)

B b2 {B (A::giveA())};