web-dev-qa-db-ja.com

「std :: string const&s」と「const std :: string&s」の違いは何ですか?

私は何かをする方法の例を探していて、この2つの変形を見ました:

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

異なるスニペット。

あなたの答えのためのTHX :)

17
Thomas Good

std::string const &const std::string &と同等です。

const std::string &は、StroustrupのC++プログラミング言語で採用されているスタイルで、おそらく「伝統的なスタイル」です。

std::string const &は他の方法よりも一貫性があります:

const-on-the-rightスタイルは常にconstを構成対象の右側に配置しますが、他のスタイルはconstを左側および右側に配置する場合があります。

Const-on-the-rightスタイルでは、constであるローカル変数は、右側のconstで定義されます:int const a = 42;。同様に、constである静的変数はstatic double const x = 3.14;として定義されます。基本的に、すべてのconstは、constメンバー関数を使用して、右側に配置する必要があるconstを含め、構成するものの右側に配置されます。

(詳しくは 「X const&x」および「X const * p」の意味は? を参照してください)。

適切なスタイルを使用する場合は、std::string const &sを無意味なstd::string & const sと誤って入力しないようにしてください。

上記の宣言は、「sconstへのstd::stringへの参照です」という意味です。参照は常にconstであるため、冗長です(別のオブジェクトを参照するように参照をリセットすることはできません)。

12
manlio

技術的には同じであり、違いはありません。しかし、一部のデバッガー(確かにlldb)ではstd::string const&と書いてもconst std::string&

5
Khurram Shehzad

他の人の主張を証明するためだけに(rttiは.name()出力にconstnessまたはvoltilnessを取り入れないことを理解しています)

このテストプログラム:

 #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;
}

gcc(4.9.2)の両方(適切な変更を加えた)msdn(vs2010)は、両方に「同じタイプ」を返します。

私はこの「答え」を「答え」としてではなく、貢献として目的としています。

編集:スコット・マイヤーズの「Effective Modern C++」の4番目の項目を読むと、私が書いた例に関する非常に興味深い隠された情報がいくつか共有されます。つまり、変数名を値で渡すため、typeidは信頼できる結果を生成しません。メソッドに値で変数を渡すと、推定された型はその一定性と揮発性と参照性を失います(神の愛はcvrに短縮されるため)。そのため、上記の例では、2つのタイプに違いがあるかどうかを証明できません。

同じアイテムは、BoostプロジェクトがTypeIndexと呼ばれるライブラリをホストし、cvrプロパティを保持すると述べています。

3
Aviv

述べたように、それらは同じタイプです。右側のconstが好きな理由の1つは、テンプレートとの関係です。ほとんどの人は、関数テンプレートを単なる置換で処理します。例えば:

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

int* p;
foo(p);

argのタイプは何ですか? const int*&、つまりconst intへのポインタへの参照を言いたいのですが、それはwrongです。テキストの置換に失敗しました。あなたが代わりにそれを書いたなら

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

次に、単純なテキスト置換により、正しいタイプint* const&が生成されます。つまり、constへのintポインタへの参照。

2
Barry

バリーが述べたように 彼の答えで 古いC構文(およびその構文のC++拡張)は、数学のように、テキスト置換の概念図をサポートしていません。

したがって、C構文を直接使用する場合、Tが単純な型である場合でも、これらの型式はですが、T constではなくconst Tを記述することをお勧めします。同等T constを書くと、char const* const p;のようなマルチレベルポインター宣言での不整合が回避され、最後のconstは移動できなくなります。これは、等価性が宣言の開始時の基本型のみであることを例示しています。

数か月前、私はconst Tを書く実験を開始し、その表記consistentlyを使用しました。マクロを使用せずに、C++ 11以降でそれが可能になったためです。一貫性をサポートするために、名前付きのtype buildersを使用します

template< class Some_type >
using Ptr_ = Some_type*;

右から左に読む代わりに

char const* const p = something;

私は普通の読み方を書くことができます

const Ptr_<const char> p = something;

それはもう少し冗長ですが、私は今、それを使用した経験があるので、それは価値があると思います(私はそれについて確信がありませんでした、それは実験でした)。

主な欠点は、この表記はC構文の直接使用と同様に(関数テンプレート)関数引数の型の推定をサポートしますが、auto宣言の型の推定をサポートしないことです。幸い、イニシャライザは簡単にconstにできるので、問題となるのは配列への参照だけです。これまでの私の実用的な解決策は、そのような場合にC(またはむしろC++)構文を直接使用することでしたが、これはおそらく言語の欠点または穴を表していると思います。他のコンテキスト。

Ptr_のような現在のタイプビルダーについては、 Githubのcppx/core_language_support/type_builders.hppファイル を参照してください。たとえば、 In_関数の引数。そしてはい、私はそれが意図を非常に明確にするので、いくらかの冗長性にもかかわらず、それも価値があることを明確にわかりました。ただし、cppxのものは実験的なものであり、変更される可能性があります。ここにリンクされている特定のファイルは移動することさえできますが、それはそこにあります。 :)