C ++ decltypeと括弧-なぜですか?


32

主題は以前議論されました が、これは重複ではありません。

decltype(a)との違いについて質問された場合decltype((a))、通常の答えは- aは変数で(a)あり、は式です。私はこの答えに満足できないと思います。

まず、a表現もです。一次式のオプションには、特に-

  • (式)
  • id式

さらに重要なことに、decltypeの表現では、括弧が非常に明示的に考慮されます

For an expression e, the type denoted by decltype(e) is defined as follows:
(1.1)  if e is an unparenthesized id-expression naming a structured binding, ...
(1.2)  otherwise, if e is an unparenthesized id-expression naming a non-type template-parameter, ...
(1.3)  otherwise, if e is an unparenthesized id-expression or an unparenthesized class member access, ...
(1.4)  otherwise, ...

したがって、問題は残ります。括弧の扱いが異なるのはなぜですか?技術論文やその背後にある委員会の議論に詳しい人はいますか?括弧を明示的に考慮すると、これは見落としではないと考えることになり、私が見落としている技術的な理由があるはずです。


2
「通常の答えは-aは変数、(a)は式です」彼らが意味することは、「(a)式でありa、式であり、変数である」ということです。
HolyBlackCat

回答:


18

それは見落としではありません。興味深いのは、Decltypeとauto(リビジョン4)(N1705 = 04-0145)に次のステートメントがあることです。

decltypeルールは、decltype((e)) == decltype(e)(EWGによって提案されたように)現在、それを明示的に述べています。

しかし、Decltype(リビジョン6)では、提案された表現(N2115 = 06-018)の変更の1つは

decltype内の括弧で囲まれた式は、とは見なされませんid-expression

言い回しに根拠はありませんが、これは少し異なる構文を使用したdecltypeの一種の拡張であると思います。つまり、これらのケースを区別することを意図したものです。

その使用法はC ++ draft9.2.8.4に示されています。

const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = 17;        // type is const int&&
decltype(i) x2;                 // type is int
decltype(a->x) x3;              // type is double
decltype((a->x)) x4 = x3;       // type is const double&

本当に興味深いのは、それがreturnステートメントとどのように機能するかです。

decltype(auto) f()
{
    int i{ 0 };
    return (i);
}

私のVisual Studio 2019は、余分な括弧を削除することを提案していますが、実際には、ローカル変数への参照を返すため、decltype((i))戻り値がint&UB になる変更が返されます。


起源を正確に指摘してくれてありがとう!decltypeは別の方法で指定できただけでなく、当初はそうだったことがわかりました。REV-6文書は、明示的にこの変な括弧の動作が追加されますが、根拠をスキップ:(私たちは今、取得したいと答えの近くにいるのを推測..
Ofek Shilon

それでも、2つの別個の関数に対して、2つの別個のキーワードにすることによって愚かな問題を解決することを提案した人はいませんか?委員会の最大の失敗の1つ(歴史的に強制されていない多くのエラーを引き起こした)。
curiousguy

13

括弧の扱いが異なるのはなぜですか?

括弧の扱いは異なりません。別に扱われるのは括弧なしのid式です。

括弧が存在する場合、すべての式に通常の規則が適用されます。タイプと値のカテゴリが抽出され、のタイプにコード化されdecltypeます。

便利なコードをより簡単に記述できるように、特別な規定があります。decltype(メンバー)変数の名前に適用する場合、通常、式として扱われるときに変数のプロパティを表す型は必要ありません。代わりに、変数を宣言するのに必要な型だけが必要です。大量の型特性を適用する必要はありません。そして、それdecltypeはまさに私たちに与えるために指定されたものです。

場合は、我々は表現として、変数の性質についてのケアを行い、その後、我々はまだ括弧の余分なペアで、かなり簡単にそれを得ることができます。


だから、ためintメンバーiadecltype(a.i)されてintいる間decltype((a.i))であるint&(と想定aされていませんかconst)?式a.iは割り当て可能ですか?
n314159

1
@ n314159-それはそれの要点です。式a.iは非const lvalueであるため、の非const lvalue参照型を取得し(a.i)ます。
StoryTeller-Unslander Monica

「すべての式の通常の規則」で、型が参照であることを示すのはなぜですか?なぜ「式としての変数のプロパティ」に参照であるというプロパティが含まれているのですか?それはいくつかの自然なデフォルトですか?
Ofek Shilon

1
@OfekShilon-それらの型は参照ではありません。式のタイプが参照として分析されることはありません。しかし、dectlypeは型にのみ解決できます。これは、式の型だけでなく、その値のカテゴリも伝えることを目的としています。値カテゴリは、参照タイプによって体系化されています。&lvalues は、xvaluesは&&、prvaluesは参照型ではありません。
StoryTeller-Unslander Monica

@StoryTeller正確には、式のタイプと非式のタイプの間に「自然な」違いはありません。これは区別を人工的なものにします。
Ofek Shilon

1

C ++ 11より前の言語では、2種類の情報を取得するためのツールが必要です。

  • 式のタイプ
  • 宣言された変数の型

この情報の性質上、機能は言語で追加する必要がありました(ライブラリでは実行できません)。それは新しいキーワードを意味します。この規格は、このために2つの新しいキーワードを導入することができました。たとえばexprtype、式のタイプdecltypeを取得したり、変数の宣言タイプを取得したりします。それは明確で幸せな選択肢だったでしょう。

ただし、標準委員会は常に、古いコードの破損を最小限に抑えるために、新しいキーワードを言語に導入ないように最善を尽くしています。下位互換性は、言語の中心的な哲学です。

したがって、C ++ 11では、2つの異なる目的で使用されるキーワードは1つだけですdecltype。2つの用途を区別する方法は、別の扱いdecltype(id-expression)方です。それは委員会による意識的な決定であり、(小さな)妥協でした。


これをcppの話で聞いたことを覚えています。しかし、私はソースを見つけることを望んでいません。誰かがそれを見つけたら素晴らしいです。
bolov

1
C ++は歴史的に多くの新しいキーワードを追加しました。多くはアンダースコアなしで、いくつかは1つの英語の単語を含みます。理性は本当にばかげています。
curiousguy

@curiousguy導入されたすべてのキーワードは既存のユーザーシンボルと衝突するため、委員会は新しい予約済みキーワードを言語に追加する決定に大きな重点を置きます。それはばかげたイモではありません。
bolov

真実でexportはない:導入されました。あなたが持つことができる場合はexport、あなたのようなものを持つことができます(以前にすべてのテンプレートは、デフォルトの「エクスポート」によってでした)decltypeconstexpr。明らかにregister、別の言語で追加すると問題が発生します。
curiousguy

@bolovありがとうございます!(1)この推測または知識ですか?余分なキーワードを避けることが動機であった議論を知っていますか?(2)id式が「式として」使用される場合、実際に別の方法で処理する必要がある例を挙げられますか?(これはどういう意味ですか?)
Ofek Shilon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.