2017-06-13 3 views
5

私は、と同様に動作する、より古いコードベースのビットパックの整数に置き換わるFlagsクラスを持っています。より新しいクラスを遵守するために、intタイプからの暗黙的な変換を禁止したいと思います。単一の値に対して暗黙の変換を許可する

enum class Flag : unsigned int { 
    none = 0, 
    A = 1, 
    B = 2, 
    C = 4, 
    //... 
}; 

class Flags { 
public: 
    Flags(); 
    Flags(const Flag& f); 
    explicit Flags(unsigned int); // don't allow implicit 
    Flags(const Flags&); 

private: 
    unsigned int value; 
}; 

私だけFlagFlagsタイプから暗黙の建設や割り当てを可能にしたいと思います。

void foo(const Flags& f); 

foo(Flags(0)); // ok but ugly 
foo(1); // illegal because of explicit constructor 
foo(0); // illegal, but I want to allow this 

これが可能である:しかし、私はまだいくつかの関数リテラル0を受け入れるようにFlagsパラメータを取るの呼び出しではなく、他の整数をご希望ですか?他の値を許可しないで0を暗黙的に変換できるようにするには?

+0

「0」はなぜ特別なのですか? – tadman

+1

void *を取るコンストラクタを追加して、0で呼び出すことができます。次に、ポインタがnullであることをctorにアサートします。それが頭に浮かぶ最初のことは、おそらくより清潔な方法でしょう。リテラル1は暗黙的にvoidに変換されません* –

+0

@tadmanビットパックされた整数をとる関数呼び出しでは、ビットを渡しません。私のコードベースには、ビットベクトルにオプションのパラメータが格納されている関数呼び出しがたくさんあります。多くの場合、リテラル0で呼び出しが行われます。 – Rakurai

答えて

6

一つのアプローチ:

void*を取るコンストラクタを追加します。

リテラル0は暗黙的にvoid*ヌルポインタに変換可能であり、リテラル1はノンポインタに変換されるため、これにより、望ましい動作が示されます。安全のために、ポインタがNULLであることをアサートすることができます。

欠点は、あなたのクラスが暗黙的にvoid *に変換可能なものから構築可能であることです。予期せぬものがコンバーチブルなので、例えばがまだ存在していなかったので、はvoid*に変換されました。基本的にはハックです。

しかし、潜在的な落とし穴に気付いている限り、これはプロジェクトでうまくいく可能性があります。

編集:

は実は、私は、これはより安全にする方法を思い出しました。 void*の代わりに、プライベート型へのポインタを使用します。

それは次のようになります。

class Flags { 
private: 
    struct dummy {}; 
public: 
    Flags (dummy* d) { ... } 
    ... 
}; 

リテラル0変換がまだ動作し、それはいくつかのユーザー定義型が誤って意図せずFlags::dummy *に変換するのはかなり難しくなります。

関連する問題