13

私はついにについて読み始めましたが、なぜ末尾の戻り値の型が必要なのか理解できません。

問題を強調するために使用される次の例に出くわしました。

template<class Lhs, class Rhs>
  decltype(lhs+rhs) adding_func(const Lhs &lhs, const Rhs &rhs) {return lhs + rhs;} 

decltype(lhs+rhs)識別子lhsrhsは解析フェーズの後でのみ有効であるため、この例は正しくありません。

私の質問は、decltype型解決のタイミングについてだと思います。私が間違っていなければ、キーワードdecltypeはコンパイル時に式の型を決定するために使用されます。

decltypeすべての解析が完了した後に型解決を実行することのマイナス面は見当たりません(上記の例では問題なく機能します)。これは問題を解決するためのより簡単な方法だったと思います...

代わりに、C++11 標準は末尾の戻り値の型を提供します。

template<class Lhs, class Rhs>
  auto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs) {return lhs + rhs;}

末尾の戻り型の他の使用法が見当たらないので、何かが欠けていることは間違いありません。私の推論のどこに欠陥がありますか?

decltype完全な関数本体を解析した後に型解決を行うことも同様に機能するため、trailing-return-types は非常に複雑なソリューションのように思えます。

4

2 に答える 2

18

すべての解析が完了した後に decltype に型解決を実行させることの欠点は見当たりません (上記の例では問題なく機能します)。

欠点は、C++ の構文解析および処理モデルの基本的な基盤を根本的に変更しないと不可能だということです。

あなたが提案したことを行うために、コンパイラは構文を見て、decltype構文の内容の基本的な字句解析を行う必要があります。次に、ソース ファイルをさらに解析します。後の時点 (いつ?) で、「ねえ、前に見たもの? 今からすべての解析作業を行うつもりです」と判断します。

原則として、C++ はシンボル定義の先読みをサポートしていません。C++ 解析フレームワークの基本的な前提は、シンボルが使用される前に宣言されていない場合、コンパイラ エラーであるということです。

クラスは先読みで回避できますが、メンバーに関してのみです。これは、id-expression がメンバー変数を参照している可能性がある場合 (つまり、スコープ内で既に宣言されているローカル変数またはグローバル変数を参照していない場合) が明確であるためです。id-expression が正確に何を参照しているかわからない場合は、そうではありません。

さらに、あなたが提案することはあいまいさを生み出します。これは何を意味するのでしょうか:

int lhs;

template<class Lhs, class Rhs>
  decltype(lhs+rhs) adding_func(const Lhs &lhs, const Rhs &rhs);

decltype 構文は、グローバルlhs変数またはローカルlhs関数パラメーターを参照していますか?

現在の方法では、これら 2 つの間に明確な線引きがあります。

int lhs;
float rhs;

template<class Lhs, class Rhs>
  decltype(lhs+rhs) adding_func1(const Lhs &lhs, const Rhs &rhs);
template<class Lhs, class Rhs>
  auto adding_func2(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs);

adding_func1グローバル変数を参照します。adding_func2関数パラメータを参照します。

したがって、地球上にあるすべての C++ コンパイラを根本的に壊すことができます。または、単に戻り値の型を後で指定することもできます。

または、C++14 のアプローチを採用して、それをまったく述べなくてもかまいません。

于 2013-05-20T14:29:22.867 に答える