Code plus simple que lambda pour un constructeur appelant qui utilise une fonction de paramètre de sortie pour initialiser un membre const

Dans l’en-tête, j’ai

class CSomeClass { const GUID m_guid; public: CSomeClass(); ///... } 

Et dans le fichier source

 CSomeClass::CSomeClass() , m_guid( []() { GUID g; ::CoCreateGuid(&g); return g; }() ) { } 

Comme vous le savez, les guides peuvent être utilisés comme identifications non destinées à être modifiées. Étant donné que la fonction ::CocreateGuid() fournit ce que je veux en tant que paramètre de sortie, au lieu de le renvoyer, je ne peux pas utiliser directement un simple appel à la fonction pour initialiser le champ membre m_guid, qui est constant.

Ainsi, une conséquence de sa constance est qu’il doit être initialisé avant le crochet d’ouverture de la liste des initialiseurs et ne doit donc pas simplement être appelé avec un appel à ::CocreateGuid() dans le corps du constructeur.

Existe-t-il un moyen plus simple de l’initialiser que cette expression lambda?

Lorsque l’expression lambda est correcte, j’utiliserais une fonction d’assistance pour cela:

 GUID create_guid() { GUID g; ::CoCreateGuid(&g); return g; } CSomeClass::CSomeClass() : m_guid(create_guid()) {} 

De plus, create_guid() a une signification en soi et peut être réutilisé (même si en faire un détail d’implémentation est possible / correct).

Vous devriez envisager de placer le GUID dans sa propre classe:

 class CGUID { public: CGUID() { CoCreateGuid(m_guid); } const GUID& guid() const { return m_guid; } // Maybe some useful functions: bool operator==(const CGUID&) const; private: GUID m_guid; }; 

Maintenant, vous pouvez utiliser ce qui précède en tant que membre:

 class CSomeClass { const CGUID m_guid; ... 

Ici, nous résumons votre modèle:

 template A co_make( HRESULT(*f)(A*) { A a; HRESULT hr = f(&a); Assert(SUCCEEDED(hr)); if (!SUCCEEDED(hr)) throw hr; return a; } CSomeClass::CSomeClass() m_guid( co_make(&::CoCreateGuid) ) {} 

où nous détectons l’échec et affirmons puis jetons si tel est le cas.

Je ne suis pas sûr que ce soit plus simple.

Vraiment, écrivez une fonction GUID make_guid() , collez-la dans un en-tête et appelez-la.

Votre proposition est le moyen le plus simple d’initialiser le membre d’instance constante.

En fait, il ne faut pas avoir peur des lambdas. En général, il est recommandé d’utiliser un nouveau style dans lambdas pour les initialisations complexes de constantes et de références, car elles partagent la propriété d’être initialisées uniquement au moment de la déclaration (ou du membre d’instance). initialisation dans la liste des initialiseurs).

De plus, votre code déclenche “l’optimisation de la valeur de retour nommée” et il n’y a pas de construction de copie au retour de lambda.

L’interface avec CoCreateGuid est déficiente car elle nécessite un argument de sortie.

Si vous insistez pour ne pas utiliser le lambda, je pense que l’alternative la plus pratique est de, dans le corps du constructeur, dématérialiser à l’aide de const_cast pour le transmettre à CoCreateGuid.

Notez que si vous entrez dans le corps d’un constructeur, le langage considère que tous les membres individuels ont été correctement initialisés, et invoquera des destructeurs pour eux si une exception se produit. Cela change énormément le fait que quelque chose soit initialisé dans la liste d’initialisation ou gauche. avec un motif binary de déchets.

Enfin, malheureusement, vous ne pouvez pas simplement appeler CoCreateGuid avec une référence démystifiée à m_guid dans le lambda, car le lambda renverra toujours une valeur et écrasera le membre. C’est essentiellement la même chose que ce que vous avez déjà écrit (à l’exception du constructeur par défaut de g )

Ce serait plus simple si vous m_guid tant que membre d’instance mutable , par opposition à const . La différence est que mutable est comme un const pour les utilisateurs d’une classe mais une lvalue parfaitement fine dans la classe