Erreur C2228 lors de la construction boost :: objet fonction dans la liste des arguments du constructeur
-
13-09-2019 - |
Question
Le code ci-dessous ne compile pas dans Visual C ++ 2005.
class SomeClass {
public: boost::function<void()> func;
SomeClass(boost::function<void()> &func): func(func) { }
};
void someFunc() {
std::cout << "someFunc" << std::endl;
}
int main() {
SomeClass sc(boost::function<void()>(&someFunc));
sc.func(); // error C2228: left of '.func' must have class/struct/union
return 0;
}
Si je mets entre parenthèses autour de l'argument du constructeur SomeClass ou construit l'objet boost :: fonction en dehors de la liste des arguments, il compile bien.
SomeClass sc((boost::function<void()>(&someFunc)));
// or
boost::function<void()> f(&someFunc);
SomeClass sc(f);
Quel est le problème avec le code précédent?
La solution
Il est une déclaration de fonction pour une fonction qui prend une référence à un boost:function <void()>
et retourner un SomeClass
. Vous pouvez mémoriser la règle suivante, qui se révèle applicable à de nombreux autres cas d'homonymie. Vous trouverez des descriptions de ces cas dans la section 8.2
de la norme C ++.
Toute construction qui pourrait être une déclaration sera considérée comme une déclaration
Cela signifie, les éléments suivants seront pris comme une déclaration de paramètre, avec des parenthèses superflues
boost::function<void()>(&someFunc)
Si vous supprimez les parenthèses, cela deviendra clair
boost::function<void()> &someFunc
Et donc, toute déclaration ne plus déclarer un objet, mais une fonction
SomeClass sc(boost::function<void()> &someFunc);
Pour résoudre ce problème, utilisez la distribution notation
SomeClass sc((boost::function<void()>)&someFunc);
Ou mettre des parenthèses autour de l'expression entière, comme vous l'avez fait.
Voici la norme dans toute sa gloire 8.2
:
L'ambiguïté découlant de la similitude entre une fonction de style fonte et une déclaration mentionnée à 6.8 peut également se produire dans le contexte d'une déclaration. Dans ce contexte, le choix est entre une déclaration de fonction avec un ensemble redondant de parenthèses autour d'un nom de paramètre et une déclaration d'objet avec une fonction de style cast comme initialiseur. Tout comme pour les ambiguïtés mentionnées à 6.8, la résolution est de considérer toute construction qui pourrait être une déclaration une déclaration. [Note: une déclaration peut être explicitement désambiguïsé par un casting de style non-fonctionnement, par un = pour indiquer l'initialisation ou en supprimant les parenthèses redondantes autour du nom du paramètre. ]
Notez que pour contrôler la priorité, vous êtes autorisé à introduire entre parenthèses à peu près partout, comme dans les domaines suivants
int (((((((a))))))) = 3;
int (*(pa)) = &a;
Autres conseils
Ceci est connu comme "le plus contrariant Parse de C ++" (de une livre de Scott Meyers a appelé efficace STL).
réponse ci-dessus , le compilateur préfère interpréter la ligne problématique comme une déclaration de fonction.