2017-04-24 2 views
10

クラス内でstatic constexprを使用すると、クラス定義外のコードが必要になるため(this questionを参照)、私の定数をenum { my_const = 123; }で定義することに慣れています。しかし、機能体はどうですか?最近、私はちょうど(でも実際にconstにそれらを悩まないで)その機能にconstexpr変数を持つ人々に気付いてきた、と私は私の、私は私の関数内で定数のどちらを好むべきですか:constexpr constまたはenum?

int foo(int x) 
{ 
    enum : int { bar = 456 }; 
    return x + bar; 
} 

で時代遅れだ馬鹿だかどうかを疑問に思いました問題は:constexpr変数ではなく、関数本体内でenumを使用することに利点がありますか?

+3

C++ 1zが出てきて(おそらく今年7月)、主流のコンパイラサポートを受けると、自動的にインラインになるので、クラス内で 'static constexpr'変数を使うことができます。しかし、関数の場合、定数の関数の中に 'enum'を宣言することを意味しますか? –

+0

@DanielH:はい、編集を参照してください。 – einpoklum

+3

関数本体の中には利点がないことはほとんど確信しています(非静的変数はリンケージを必要とせず、静的変数も関数自体のものを共有することができます)。そして、実際にはC++標準では許可されていないと思います(たとえ一部のコンパイラがそれを拡張子として許しているとしても)。特に、コードをコンパイルするためにg ++(バージョン6.3)を手に入れることはできません。私はコメントの代わりに答えを出すことはそれほど確かではありませんが、間違っていると私は驚くでしょう。 –

答えて

18

ODRの存在がbarの場合は、constexpr int bar = 456;の場合はenum : int { bar = 456 };では不可能です。

これは、どちらの側でも利点である場合とそうでない場合があります。例

int baz(int const* ptr) { 
    if (ptr) return 7; return -1; 
} 
int foo(int x) 
{ 
    // enum : int { bar = 456 }; 
    constexpr int bar = 456; 
    return x + baz(&bar); 
} 

enumバージョンがコンパイルされないために

constexpr int 1はありません。 constexpr intは左辺値になります。列挙子(列挙された列挙定数の1つ)はできません。

列挙値は実際にはintではなく、constexpr intは実際にはintです。これを渡すと問題になることがあります。

template<class T> 
void test(T) { 
    static_assert(std::is_same<T,int>::value); 
} 

1つはテストに合格します。もう片方はしません。

また、トークンの使用方法によっては、メリット、デメリット、または無意味なクォークになる可能性があります。 Yakkの(しかし、これは私自身のテイクである)@に基づいて

+0

私はODRが何であるか知っていますが、ここでは「ODR存在」とは何を意味するのか分かりません。コンパイルされていない列挙型バージョンについては、AFAIKは実際にはコンパイルすべきではありません。あなたが言ったように、私はbarという名前のint変数を望んでおらず、ちょうどコンパイル時に 'int'のように振る舞います。 2番目のバージョンがコンパイルされるのはちょっと驚いています。つまり、バーにはメモリ内にスペースが割り当てられている必要があります。 – einpoklum

+2

コンパイラがこれが必要であると判断した場合には、メモリ内にスペースが割り当てられます。あなたが住所を取っていない場合、これはそうではありません。たとえコンパイラがどこかに番号を格納したかったとしても、おそらくレジスタを使用し、通常は値を格納したくないということです。 'constexpr int'は、ほとんどの場合、コンパイル時にのみ存在する値です。 –

+0

@einpok ODRとは、値だけでなく変数の* identity *が必要であることを意味します。 'constexpr'値は、コンパイル時に計算できる値を持ちますが、それもIDを持つことができます。列挙型の値は同一性を持つことはできません。アイデンティティーの存在は、「実際にメモリに存在する」と似ていますが、あまりよくありません。アイデンティティを持つものは、メモリを最適化することができます。 「アイデンティティ」は標準からの用語ではなく、説明するためのものです。 – Yakk

1

ワンライナー:あなたはあなたの定数は、実行時に、「変数」として存在させることができない場合enumベースの定数を使用して

が必要になる場合があります。列挙型では、あなたが何をしているにせよ、それはアドレスを持たず、メモリスペースも占有されません(コンパイラの最適化のためにだけではありません)。

他のケースでは、一方を他方よりも優先させる魅力的な理由はないようです。

+0

odrが使用されていない定数のためのスペースを占める「変数」はありません。これは最適化に依存していないので、言語によってかなり保証されています(標準では実際に「メモリ空間が占有されている」とは言わないので、まったくその言葉では言いません)。 –

+0

無駄なスペースに関する誤った(IMHO)の懸念のために、コードを細工し、新しいタイプ(列挙型)を発明することは、間違った問題に集中しています。 [関連する名前付き定数のセットを表すために列挙を使用する](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Renum-set)、[名前のない列挙を避ける](https:// github。 "代わりにconstexprの値を使用してください。") –

+1

@ cppCoreGuidelines/blob/master/CppCoreGuidelines.md#Renum-unnamed)(このようなコードは、整数定数を指定する便利な方法がある前に書かれたコードでは珍しいことではありません) Jonathan Wakely:これが誤っているかどうかの問題は、文脈によって異なります。誰かが 'constexpr'フィールドのためのスペースの割り当てを引き起こすかもしれません、そして、異なるメモリレイアウトは、他の場所でコンパイルされたコードとの非互換性を引き起こすかもしれません。 – einpoklum

関連する問題