web-dev-qa-db-fra.com

C++ 11 - déclaration des membres de données non statiques comme "auto"

C++ 11 permet-il de déclarer des membres de données non statiques comme "auto" s'ils sont initialisés dans la déclaration? Par exemple:

struct S
{
    auto x = 5;  // in place of 'int x = 5;', which is definitely allowed
};

GCC 4.7 rejette le code ci-dessus, alors qu'il accepte int x = 5;.

En supposant que ceci ne soit pas un bogue du compilateur mais que la norme ne le permet vraiment pas, pourquoi pas? Ce serait aussi utile que de déclarer des variables locales auto.

40
HighCommander4

La règle d'interdiction des membres non statiques est énoncée au 7.1.6.4, clause 4:

Le spécificateur de type automatique peut également être utilisé pour déclarer une variable dans la condition d'une instruction de sélection (6.4) ou d'une instruction d'itération (6.5), dans le type-specifier-seq dans le nouveau-type-id ou le type-id d'un new-expression (5.3.4), dans une déclaration for-range et dans la déclaration de static data member avec un initialisateur entre accolades ou égales qui apparaît dans la spécification de membre d'une définition de classe (9.4.2).

J'ai trouvé la raison d'être statique ici , ce qui reflète la manière dont James McNellis l'explique dans le commentaire.

Un organisme national n'aime pas autoriser le spécificateur de type automatique pour non-statique. D'un courriel aux auteurs:

    template< class T >
    struct MyType : T {
      auto data = func();
      static const size_t erm = sizeof(data);
    };

Afin de déterminer la disposition de X, nous avons maintenant une recherche de nom en deux phases et une ADL. Notez que func peut être un type ou une fonction; on peut le trouver dans T, l’espace de noms de MyType, l’associé espace (s) de noms de T lorsqu'il est instancié, l'espace de noms global, un Un espace de noms anonyme, ou tout espace de noms soumis à une directive using . Avec précaution, nous pourrions probablement lancer une recherche concept_map pour avoir de la chance . En fonction de l'ordre d'inclusion de l'en-tête, je pourrais même obtenir des résultats différents pour ADL et enfreindre la règle de définition unique - qui n'est pas nécessaire pour être diagnostiqué. 

En raison de cette controverse, les auteurs ne proposent plus cette auto être autorisé pour les membres de données non statiques.

Donc, fondamentalement, en fonction de l'ordre d'inclusion de l'en-tête, le type de data pourrait être très différent. Bien entendu, auto x = 5; n'aurait pas besoin de dépendre de la recherche de nom en deux phases ni de la liste ADL. Toutefois, je suppose qu'ils en ont fait une règle "générale", car ils devraient créer des règles individuelles pour chaque cas d'utilisation, rendre les choses très compliquées.

Dans le même article, l’auteur propose de supprimer cette restriction, mais il semble que cette proposition a été rejetée, probablement en raison des raisons susmentionnées, ainsi que pour que le comportement attendu puisse être le même, quel que soit l’initialisateur.

56
Jesse Good

Pour les autres:

En utilisant C++ 17, cela est indirectement possible (déduction automatique du type de membre non statique). Pour ce faire, vous devez utiliser des modèles et des guides de déduction:

template< class data_t>
struct MyType 
{
    data_t data;
    static constexpr auto data_size = sizeof(data_t);

    MyType( data_t && p_data ) : data(p_data) {}
};

template< class data_t>
MyType(data_t &&) -> MyType<std::remove_reference_t<data_t>>;

Je ne sais pas comment, mais les membres de cette auto ont vraiment besoin de maîtriser la langue sans eux, certains schémas sont quasiment impossibles. 

Le scénario ci-dessus fonctionne pas si le lambda capture un membre de la classe par référence. C'est un modèle utile pour les classes hautement compensables qui évitent l'utilisation de fonctions de type effacé. Quelque chose que je fais régulièrement sur les systèmes embarqués.

https://godbolt.org/z/W-K9Uk

Vous pouvez modifier la langue en soumission en permettant à un lambda de référencer un membre d'une classe inexistante à l'aide de placement-new et offset_of, mais c'est ridicule et ne devrait pas être nécessaire.

1
David Ledger