web-dev-qa-db-fra.com

Quelle est la différence entre "std :: string const & s" et "const std :: string & s"?

Je cherchais des exemples sur la façon de faire quelque chose et j'ai vu ces deux variantes:

std::string const &s;
const std::string &s;

dans différents extraits.

merci pour votre réponse :)

17
Thomas Good

std::string const & est équivalent à const std::string &.

const std::string & est le style adopté dans Stroustrup Le langage de programmation C++ et est probablement "le style traditionnel".

std::string const & peut être plus cohérent que l'alternative:

le style const-on-the-right place toujours le const à droite de ce qu'il constitue, tandis que l'autre style place parfois le const à gauche et parfois à droite.

Avec le style const-on-the-right, une variable locale qui est const est définie avec le const à droite: int const a = 42;. De même, une variable statique const est définie comme static double const x = 3.14;. Fondamentalement, chaque const se retrouve à droite de la chose qu'il constitue, y compris le const qui doit être à droite: avec une fonction membre const.

(voir Que signifient "X const & x" et "X const * p"? pour plus de détails).

Si vous décidez d'utiliser le style const-on-the-right, assurez-vous de ne pas taper std::string const &s comme absurde std::string & const s:

La déclaration ci-dessus signifie: "s est une const référence à un std::string ". C'est redondant car les références sont toujours const (vous ne pouvez jamais réinitialiser une référence pour la faire référence à un autre objet).

12
manlio

Techniquement, c'est la même chose et cela ne fait aucune différence. Mais dans certains débogueurs (lldb à coup sûr), vous verrez std::string const& même si vous avez écrit comme const std::string&.

5
Khurram Shehzad

Juste pour prouver les assertions des autres (je comprends que rtti ne prend pas la constance ou la tension dans la sortie .name())

ce programme de test:

 #include <string>
 #include <iostream>

 using std::string;
 using std::cout;
 using std::cin;

  using std::endl;

  int main()
  {
    std::string t = "BLABLA" ;
    std::string t1 = "BLABLA" ;
    std::string const &s = t;
    const std::string &d = t1;


if (typeid(d) == typeid(s)) 
    cout << "d and s are the same type according to the rtti" << endl;

else
    cout << "d and s are the NOT the same type according to the rtti" <<  endl;
    // here the raw output is exactly the same for both
    cout << typeid(d).raw_name() << endl << typeid(s).raw_name() << endl; 

    cin >> t;
    return 0;
}

les deux pour gcc (4.9.2) (avec les modifications appropriées) msdn (vs2010) renvoie "même type" pour les deux.

Je vise cette "réponse" comme une contribution et non comme une "réponse".

EDIT: La lecture du point 4 dans "Effective Modern C++" de Scott-Meyers partage des informations cachées vraiment intéressantes sur l'exemple que j'ai écrit. En bref, typeid ne donne pas de résultats fiables car nous passons des noms de variables par valeur . Lorsque nous transmettons à une méthode une variable par valeur, le type déduit perd sa constance, sa volatilité et sa référence (car l'amour de Dieu sera raccourci en cvr). C'est pourquoi l'exemple ci-dessus ne prouve pas s'il y a une différence entre les deux types.

Le même élément indique que le projet Boost héberge une bibliothèque appelée TypeIndex, qui préserve les propriétés cvr.

3
Aviv

Comme indiqué, ils sont du même type. L'une des raisons d'aimer le const à droite est la façon dont il joue avec les modèles. La plupart des gens traitent les modèles de fonction par simple substitution. Par exemple:

template <class T> void foo(const T& arg);

int* p;
foo(p);

Quel est le type de arg? Tu veux dire const int*&, c'est-à-dire une référence à un pointeur sur const int, mais c'est faux. La substitution de texte vous a échoué. Si vous l'avez écrit à la place comme

template <class T> void foo(T const& arg);

La simple substitution de texte donne alors le type correct: int* const&. Autrement dit, une référence à const pointeur vers int.

2
Barry

Comme Barry l'a noté dans sa réponse l'ancienne syntaxe C (et l'extension C++ de cette syntaxe) ne prend pas en charge la vue conceptuelle de la substitution de texte, comme en mathématiques.

En utilisant directement la syntaxe C, c'est généralement une bonne idée d'écrire T const, ne pas const T, même si T est un type simple, ces expressions de type sont équivalent. L'écriture T const évite également les incohérences dans une déclaration de pointeur à plusieurs niveaux comme char const* const p;, où le dernier const ne peut pas être déplacé. Ce qui illustre que l'équivalence ne concerne que le type de base au début d'une déclaration.

Il y a quelques mois, j'ai commencé une expérience en écrivant const T, et en utilisant cette notation toujours. Parce que c'est désormais possible après C++ 11, sans utiliser de macros. Pour soutenir la cohérence, j'utilise des constructeurs de types nommés comme

template< class Some_type >
using Ptr_ = Some_type*;

de sorte qu'au lieu de la lecture de droite à gauche

char const* const p = something;

Je peux et écris le sens de lecture ordinaire

const Ptr_<const char> p = something;

C'est un peu plus verbeux, mais maintenant, avec une certaine expérience de son utilisation, je pense que ça vaut le coup (je n'en étais pas sûr, c'était une expérience).

L'inconvénient principal est que même si cette notation prend en charge la déduction de type pour les arguments de fonction (modèle de fonction) tout comme l'utilisation directe de la syntaxe C, elle ne prend pas en charge la déduction de type pour les déclarations auto. Heureusement, puisqu'un initialiseur peut facilement être fait const, le seul cas problématique est la référence au tableau. Jusqu'à présent, ma solution pragmatique a été d'utiliser la syntaxe C (ou plutôt C++) directement dans de tels cas, mais je pense que cela représente une lacune ou un trou dans le langage, éventuellement avec une solution générale qui rendrait les choses beaucoup plus faciles également dans d'autres contextes.

Pour mes constructeurs de types actuels comme Ptr_, voir le fichier cppx/core_language_support/type_builders.hpp sur Github . Ils comprennent par exemple In_ pour les arguments de fonction. Et oui, j'ai trouvé que ça valait aussi la peine, en toute clarté, malgré une certaine verbosité, car cela rend l'intention très claire. Cependant, le truc cppx est expérimental et sujet à changement. Le fichier spécifique lié ici peut même être déplacé, mais ce sera le cas. :)

2