2017-02-02 4 views
24
#include <type_traits> 

struct foo; 
int main() 
{ 
    const foo *bar; 

    static_assert(std::is_const<decltype(*bar)>::value, 
        "expected const but this is non-const!"); 
} 

これは予期せぬエラーであるstatic_assertを発生させます。これはconst参照のthis questionと幾分似ていますが、全く同じではありません。Tのvalue_typeがconstであっても、なぜstd :: is_const :: value 'false'ですか?

私の場合、逆参照barは、その型としてconst fooのインスタンスを与える必要がありますが、それ以外の場合はstd::is_constと言います。

+1

'const foo * bar'はconst _pointer_を作成しますが、それが指す値は_not_ constです。 – Aganju

+16

@Aganjuいいえ、それは 'foo * const bar;です。 – greatwolf

+7

' const foo * bar'は 'foo const * bar'と同じですが、' foo * const bar'とは異なります –

答えて

35

まもなく、参照またはconst型へのポインタがconst型ではないためです。
decltype(*bar)const fooではありません。それはconst foo &であり、実際には異なる獣です。


here与えられた例を考えてみましょう:

std::cout << std::is_const<const int *>::value << '\n'; // false 
std::cout << std::is_const<int * const>::value << '\n'; // true 

我々はstd::is_const<const int *>::valueがfalseでstd::is_const<int * const>::valueが真であることがわかります。
const int *では、型がconstのポインタであり、それはis_const(実際には標準)の意図したconst型ではないからです。 int * constでは、const修飾子はポインタータイプに適用され、ポインタータイプには適用されません。したがって、ポインタータイプに関係なく、constタイプになります。
何か同様のものがconst foo &に適用されます。これはconstの参照です。

あなたは代わりに、これを使用して解決することができます:

static_assert(std::is_const<std::remove_reference_t<decltype(*bar)>>::value, "expected const but this is non-const!"); 

、あるいはこれ、あなたが実際に*barを行う必要はありませんのために:この場合

static_assert(std::is_const<std::remove_pointer_t<decltype(bar)>>::value, "expected const but this is non-const!"); 

でポインタを削除/参照remove_pointer_t/remove_reference_tあなたのタイプはconst fooになります。これは実際にはconstタイプです。サイドノートとして


、上記の例は、C++ 14っぽいstd::remove_reference_tstd::remove_pointer_t型形質を使用します。
それは次のように、簡単にC++ 11にコードのこれらの行を変えることができます:

static_assert(std::is_const<typename std::remove_pointer<decltype(bar)>:: type>::value, "expected const but this is non-const!"); 

より多くの詳細を与えるためにその答えにいくつかのコメントを言及する価値があります:

  • @DanielFischerの質問のおかげで:

    decltype(*bar)はなぜですか? const fooではなくconst foo&

    単項*演算子は、間接実行します:それはされている表現を、私は、言語弁護士ないんだけど、私はそれが[expr.unary.op]/1(強調鉱山)から推定することができますね

    適用されるものは、オブジェクト型へのポインタ、または関数型へのポインタでなければならず、その結果は、式が指すオブジェクトまたは関数を参照する左辺値です。

    そして[dcl.type.simple]/4.4(強調鉱山):

    さもなければ、eが左辺値である場合、decltype(e)はTが電子の一種であるT &、です。

    どちらも、作業草案を参照してください。

  • コメントの@LightnessRacesInOrbitに感謝します。 decltype(*bar)const foo &であることは、*barconst foo &ではないので、decltypeという面白いC++の奇妙なものです。

+10

明示的に言及する価値があります: 'decltype * bar) 'は' const foo'ではありません。 'const foo&' –

+1

@RyanHainingということは知っておいて、それは欠けていた部分です。 – greatwolf

+1

@RyanHaining最初の行に追加されました。 – skypjack

関連する問題