web-dev-qa-db-ja.com

C ++静的定数メンバー変数の使用

機能するためにいくつかの定数を必要とするクラスがあるとしましょう。いくつかのメンバー関数では、これらの定数を使用する必要があります。 #defineの使用は衝突を引き起こす可能性があるため、眉をひそめています。定数は8または16ビットの16進パターンで、uint8_tまたはuint16_tとして保存されます。また、これらの定数はクラスのインスタンスごとに変更されないため、定数のコピーを1つだけ保持することで、メモリ(非常に少ないメモリ)を節約できます。

不適切なもの、または単に次のようなことを行う代わりに上記を達成するためのより良い方法がありますか?

// mycode.h
// .......
class myclass {
private:
  static const uint16_t kMyClassConstant_ = 0xBEEF;
// .......
};

助けてくれてありがとう。

25
It'sPete

状況の説明を考えると、static constメンバーを使用するのが良い方法だと思います。 C++ 11では、これをstatic constexprに変更して、コンパイル時の定数であることを強調したい場合がありますが、その結果として何も効果的には変更されません。

コードのどこかでmyclass::kMyClassContant_をone-definition-rule(odr)に関連する方法で参照する場合、特に参照(const-referenceを含む)を必要とするコンテキストでは、コンパイラは定数の定義がないと文句を言います。この場合、クラス内で宣言して初期化するだけでは不十分です。これにより、宣言と定義を分離することが必要になる場合があります。

// mycode.h
class myclass {
private:
  static const uint16_t kMyClassConstant_;
};

// mycode.cpp
const uint16_t myclass::kMyClassConstant_ = 0xBEEF;

別々の宣言と定義を維持する手間を避けるために、実際の変数の代わりにインラインconstexpr関数を宣言することを好む人もいます。

// mycode.h
class myclass {
private:
  static constexpr uint16_t kMyClassConstant_()
  { return 0xBEEF; }
};

これは、odr関連の問題の多くに対する正しい回避策であり、パフォーマンスの低下は発生しません。本当に役立つかどうかは、通常の静的定数の宣言と定義を別々に保持するのがどれだけの負担になるかによって異なります。コードの進化に伴って定数が変更されないことが予想される場合は、通常の静的定数と別個の定義を使用することをお勧めします。ただし、定数の定義を頻繁に変更する場合は、定義ファイルを再コンパイルしてプロジェクトのすべての関連部分に再リンクする必要があるため、上記の関数ベースのソリューションをより良い選択肢と見なすことができます。

データ型に関する最後のコメント:std::uint16_tを使用して16ビットにすることは、これらの値の多くをコンパクトな形式で保存する必要がある場合に役立ちます。そうでない場合、実際のサイズは実際には重要ではない可能性があります。その場合、std::uint_fast16_t(16ビットよりも大きい可能性があります)の方が優れている場合があります。

44
jogojapan

型の特性を使用してこれを実装できます。

#include <type_traits>

class myclass {
private:
  typedef std::integral_constant<uint16_t , 0xBEEF> kMyClassConstant;

  // ...
};

使用されます myclass::kMyClassConstant::value

これは、整数定数を実装する目的を示しており、定数のアドレスを誤って取得することを防ぎます。

5
Jan Herrmann

C++ 17以降、inline変数にアクセスでき、odr関連の問題を処理します。いくつかのオプション:

// mycode.h
class myclass {
    static const inline uint16_t kMyClassConstant_ = 0xBEEF;
};

または、constexprとマークできる場合(この場合のように):

// mycode.h
class myclass {
    static constexpr inline uint16_t kMyClassConstant_ = 0xBEEF;
};

次のように簡略化できます。

// mycode.h
class myclass {
    static constexpr uint16_t kMyClassConstant_ = 0xBEEF;
};

C++ 17ではconstexprinlineデータメンバーのstaticを意味するためです。

4
Acorn