これは基本的な質問かもしれませんが、今のところ自分では答えがわかりません。
次のコードについて考えてみます。
template<bool b>
struct T {
static constexpr int value = (b ? 42 : 0);
};
template<bool b>
struct U {
enum { value = (b ? 42 : 0) };
};
int main() {
static_assert(T<true>::value == 42, "!");
static_assert(T<false>::value == 0, "!");
static_assert(U<true>::value == 42, "!");
static_assert(U<false>::value == 0, "!");
}
私はT
のような構造体を使用することに慣れていますが、同じ目的(主に特性の定義)で使用されるU
のような構造体を何度も見ました。
私が見る限り、どちらもコンパイル時に解決され、ほぼ同じ問題を解決しますが、T
はU
よりもはるかに読みやすいようです(まあ、私は知っています、私の個人的な意見)。
私の質問は非常に単純です。一方のソリューションがもう一方のソリューションよりも優れている技術的な理由はありますか?
さらに、そのうちの1つが実行可能な解決策ではない場合はありますか?
このように使用した場合、積分定数に目立った違いはありません。
ただし、enum
は実際には優れています。これは、真の名前付き定数であるためです。 constexpr
積分定数は、たとえばODRで使用できるオブジェクトであり、リンクエラーが発生します。
_#include <iostream>
struct T {
static constexpr int i = 42;
enum : int {x = 42};
};
void check(const int& z) {
std::cout << "Check: " << z << "\n";
}
int main() {
// check(T::i); // Uncommenting this will lead to link error
check(T::x);
}
_
check(T::i)
がコメント解除されている場合、プログラムはリンクできません。
_
/tmp/ccZoETx7.o
_:関数 `main
'内:_ccc.cpp
_:(_.text+0x45
_):` _T::i
_'への未定義の参照_collect2
_:エラー:ld
が_1
_終了ステータスを返しました
ただし、真のenum
は常に機能します。
レガシーコードだと思います。
enum { value = (b ? 42 : 0) };
c ++ 03およびC++ 11で有効なコードです。
static constexpr int value = (b ? 42 : 0);
c ++ 11でのみ有効です。
さらに、そのうちの1つが実行可能な解決策ではないケースはありますか?
どちらもC++ 11で実行可能なソリューションです。どちらを使用するかの選択は、チームによって異なります。それは政策決定の問題になるでしょう。
SergeyAによる回答 が示すように、enum
は真の定数です。 ODRはできません-それらを使用してください。 ODRできます-constexpr
を使用します。これらのどれがアプリケーションにとって望ましいかによって、enum
sとconstexpr
sのどちらを使用するかを決定できます。
SergeyAによって現在受け入れられている回答 はC++ 17以降保持されなくなりました( 定義とODR )。
以下を除いて、すべての宣言は定義です。
- .。
- (非推奨)constexpr指定子を使用してクラス内で定義された静的データメンバーの名前空間スコープ宣言
struct S {
static constexpr int x = 42; // implicitly inline, defines S::x
};
constexpr int S::x; // declares S::x, not a redefinition
したがって、C++ 17の時点では、列挙型よりも表現力のある静的constexpr定義を使用します。