2016-11-11 8 views
0

現在、構造体に基づいて整数ベースの状態を生成するかなりの解決策を考え出しています。structメンバ関数の値に基づいて状態を生成します。

この関数は、構造体のインスタンスを取得し、メンバ変数に基づいて一意の状態を生成する必要があります。

手作業でチェックしたり、すべての可能性を設定して状態を生成したりしない、きわめて簡単な解決策は何ですか?

+1

だから、この 'struct'を'ハッシュ 'したいですか? – NathanOliver

+0

hmmm ...おもしろい...うーん、ハッシュ関数..生成されたキーが整数の場合。 –

+1

あなたの質問に対する答えではなく、単なる提案です。 'true'と' false'が説明を必要とし、スピード値の数が限られているだけでは、enumを使うことができます。 'FORWARD'や' BACKWARDS'のような名前はコードで読みやすく、人々はどの値を参照する必要はありません。 – Hayt

答えて

3

ビットセットstd::bitsetまたは符号なし数値タイプ)を使用して、独自の状態を表すことができます。

あなたが必要になります。

  • 1ビットをbusyため。
  • poweredの場合は1ビットです。
  • directionの場合は1ビットです。
  • speedの2ビット。

合計で、可能なすべての組み合わせを表すには5ビットが必要です。

例:

auto status::hash() const noexcept 
{ 
    std::bitset<5> b; 
    b |= speed; // assumes only the last two bits in `speed` are used 
    b.set(4, busy); 
    b.set(3, powered); 
    b.set(2, direction); 
    return b; 
} 

wandbox example

+0

'std :: bitset'を' int8'に変換すると、不一致が発生しますか? –

+1

@CarltonBanks:不一致はありません。変換の例については、[この質問](http://stackoverflow.com/questions/19583720/convert-bitset-to-int-in-c)を参照してください。あるいは、同じロジックを使用して、 'std :: uint8_t'で直接ビット演算を行うことができます。 –

0

としてstd::bitsetとして良いが、あなたはビットフィールドを使用して、単一のバイトでstruct全体を格納することができない:

struct status { 
public: 
    status(Busy busy, Speed speed, Powered powered, Direction direction) 
     : busy{busy}, speed{speed}, powered{powered}, direction{direction}, pad{0} {}; 

    Busy busy : 1; 
    Speed speed : 2; 
    Powered powered : 1; 
    Direction direction : 1; 
    unsigned char pad : 3; // pad to 8 bits 
}; 

完全なプログラム:

#include <bitset> 
#include <iostream> 

#define ENUM_MACRO3(name, v1, v2, v3)\ 
    enum class name : unsigned char { v1, v2, v3};\ 
    std::ostream& operator<<(std::ostream& os, name var) {\ 
     switch (var){\ 
      case name::v1: return os << #v1;\ 
      case name::v2: return os << #v2;\ 
      case name::v3: return os << #v3;\ 
     }\ 
     return os;\ 
    } 

#define ENUM_MACRO2(name, v1, v2)\ 
    enum class name : unsigned char { v1, v2};\ 
    std::ostream& operator<<(std::ostream& os, name var) {\ 
     switch (var){\ 
      case name::v1: return os << #v1;\ 
      case name::v2: return os << #v2;\ 
     }\ 
     return os;\ 
    } 

ENUM_MACRO3(Speed, fast, medium, slow) 
ENUM_MACRO2(Busy, handling, not_handling) 
ENUM_MACRO2(Powered, on, off) 
ENUM_MACRO2(Direction, forwards, backwards) 

struct status { 
public: 
    status(Busy busy, Speed speed, Powered powered, Direction direction) 
     : busy{busy}, speed{speed}, powered{powered}, direction{direction}, pad{0} {}; 

    Busy busy : 1; 
    Speed speed : 2; 
    Powered powered : 1; 
    Direction direction : 1; 
    unsigned char pad : 3; // pad to 8 bits 
}; 

int main() 
{ 
    status s{Busy::not_handling,Speed::slow,Powered::off,Direction::backwards}; 

    std::cout << "Data has size of " << sizeof(status) << '\n'; 
    std::cout << "busy :" << s.busy << '\n'; 
    std::cout << "speed :" << s.speed << '\n'; 
    std::cout << "powered :" << s.powered << '\n'; 
    std::cout << "direction :" << s.direction << '\n'; 

    unsigned char val = reinterpret_cast<unsigned char&>(s); 
    unsigned int num{val}; 
    std::cout << num << '\n'; 
    std::bitset<8> bs{num}; 
    std::cout << bs << '\n'; 
    return 0; 
} 

生成します:

Data has size of 1 
busy :not_handling 
speed :slow 
powered :off 
direction :backwards 
29 
00011101 

心に留めておくべきいくつかのポイント:

  • Bit fieldsを移植することはできません。別の実装では、次のようになります。
    • 2バイト以上を使用してください。
    • ビットを反転させます。
    • パディングを導入して、ビットの配置を変更します。
  • 上記のプログラムはstrict aliasing ruleです。
    • したがって、ビットを直接安全な方法で設定することによって、std::bitsetでハッシュを生成するのが最善でしょう。
  • ビットフィールドが遅いです。
関連する問題