5

一時オブジェクト(たとえば、std :: string)をオブジェクトのコンストラクターに渡したいのですが:

class MyClass{
  public:
    MyClass(string a):
      a(a)
    {

    }
    string a;
};

int main(int argc, char *argv[]){
  MyClass a(string());
  cout<<a.a<<endl;
  return 0;
}

しかし、私はこのエラーを受け取ります:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:28:11: error: request for member ‘a’ in ‘a’, which is of non-class type ‘MyClass(std::string (*)()) {aka MyClass(std::basic_string<char> (*)())}’

一時オブジェクトのコンストラクター(たとえば、string( ""))に何かを渡せば、すべてが正常に機能します。なんで?

4

2 に答える 2

8

これは、C++の最も厄介な解析と呼ばれているもののインスタンスです。コンパイラは解釈します

MyClass a(string());

aaを返し、名前のないものをパラメーターとしてMyClass取るという名前 の関数のプロトタイプとして。string

stringコンストラクターの呼び出しを括弧で囲むことにより、明確にすることができます。

MyClass a((string()));

MyClassまたは、アクセス可能なコピーコンストラクターがある限り:

MyClass a = string();

C++11のアップデート

initializer_listクラスに:を取るコンストラクターがない限り、ユニバーサル初期化構文で明確にすることもできます。

MyClass a { string() };
于 2012-02-29T02:06:44.947 に答える
2

Sethがすでに指摘しているように、これは言語と式の解析方法の問題です。基本的に、コンパイラーは式を見つけると、それをシグニチャーを持つMyClass a(string())関数の宣言として解釈します(余分なものは、引数内の関数から関数へのポインター、関数への暗黙の変換から発生します)。aMyClass (std::string (*)())(*)

特定の場合にその構文を克服するためのさまざまなアプローチがあります。

MyClass a("");                // 1
MyClass b = std::string();    // 2
MyClass c(( std::string() )); // 3

最初のアプローチは、T()式を使用して右辺値を作成するのではなく、同じ出力を生成する定数リテラルを使用することです。このアプローチの欠点は、この特定のケースではリテラルを使用できますが、同じソリューションを他の型に適用できないことです(つまり、デフォルトのコンストラクターしかない独自の型がある場合)

2番目のアプローチは、代替構文を関数宣言として解析できないため、直接初期化を回避することです。このアプローチの問題は、特定の場合の結果は同じですが、コンストラクターが明示的でないことを要求することです。(つまり、コンストラクターが宣言されていると失敗しますexplicit MyClass( std::string const & ))が、それはありません

3番目のアプローチは、コンストラクターの最初の引数の周りに括弧のセットを追加することです(解析で同じ問題が発生することに注意してくださいMyClass a(std::string(), std::string()))。このアプローチ(意見)の問題は、それが醜いということですが、それ以外の点では、3つの中で最も柔軟性があります。

于 2012-02-29T02:27:13.940 に答える