中括弧付きの参照型の変数のdecltype

Dec 15 2020

次のコードを検討してください。

#include <type_traits>

int main() {
    const int& p = 42;
    auto v1 = decltype(p){};
    static_assert(std::is_same_v<decltype(v1), int>);
    
    decltype(p) v2{};
    static_assert(std::is_same_v<decltype(v2), const int&>);
    // auto v3 = X(const int&)X {};
}

のタイプはv1として推定されintます。同時に、のタイプはv2として推定されconst int&ます。の最初のステップはv1、もう1つの型エイリアスusing T = decltype(p);を追加してからを追加することとして扱うことができると思いますauto v4 = T{};。この式(decltype(p){}またはT{})はコンパイラによってどのように扱われますか?その{}部分がインスタンス化用であることは知っていますが、結果の型がv1参照型ではないのはなぜですか?

さらに別の質問:(の代わりに)明示的に記述された型を使用v3するのと同じ型の変数を宣言する方法はありますか?v1const int&decltype(p)

標準へのリンクをいただければ幸いです。

回答

1 Enlico Dec 15 2020 at 00:48

(反対派へ:スコット・マイヤーズを引用することは標準を引用することと同等ではないと思うために反対票を投じた場合、まあ...)

効果的なModernC ++から読むことができるように(そのリンクで検索することで到達できるエラッタの一部で補強されCase 2:、次の読み取りが簡単になりますが、質問に必須ではありません):

場合はParamType非参照である場合は、[...]exprの型が参照され、参照部を無視します。[...]exprがの場合はconst、それもインゴアします。の場合は、それvolatileも無視してください。

ここparamで、は宣言指定子です。これは、あなたの場合は単なるauto、つまり非参照です。

言い換えれば、あなたは、作成しているv1平野を経てauto(ないauto&、それはあなたが参照するか、あるいはであるエンティティで初期化されているかどうかは関係ありませんので、コピーによってすなわち、)constかない(またはvolatileかどうか、FWIW)、あなたがそれをコピーしているからです。

より単純なケースについて考えてみてください。

int i = 3;
int& p = i;
auto v1 = p;

限りv1懸念している、それは実際にそれが1でinitalizedされているかどうかは重要(ではないi)、または他の(pそれによって)名前と同じ、それは実体があることをどのような値のコピーを取得しますので、実体が知られています。

auto型の推定は、テンプレートの型の推定と同じように機能し(ブレース付き初期化子の処理方法の違いを除いて、この場合は関係ありません)、どちらもScottMeyersのEffectiveModern C ++を参照できます