2017-06-13 1 views
5

Ich habe eine Flags Klasse, die sich ähnlich wie std::bitset verhält, die bitpacked Ganzzahlen in einer älteren Codebasis ersetzt. Um die Einhaltung der neueren Klasse zu erzwingen, möchte ich die implizite Konvertierung von int Typen verbieten.Zulassen impliziter Konvertierung für einen einzelnen Wert

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; 
}; 

Ich mag impliziten Aufbau und Zuordnung ermöglichen, nur von den Flag und Flags Typen. Allerdings würde ich noch einige Funktionsaufrufe wie die eine Flags Parameter nehmen eine wörtliche 0, zu akzeptieren, nicht aber andere Zahlen:

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 

Ist das möglich? Soll 0 implizit konvertiert werden, während andere Werte nicht zulässig sind?

+0

Warum ist '0' hier speziell? – tadman

+1

Sie könnten einen Konstruktor hinzufügen, der void * enthält und mit 0 aufgerufen wird. Dann wird der Zeiger im ctor auf null gesetzt. Das ist das erste, was einem einfällt, vielleicht gibt es einen saubereren Weg. Literal 1 konvertiert nicht implizit in void * –

+0

@tadman In Funktionsaufrufen, die eine bitgepackte Ganzzahl enthalten, werden keine Bits übergeben. In meiner Codebasis gibt es viele Funktionsaufrufe, wo ein Bitvektor optionale Parameter enthält, und oft wird der Aufruf mit einem Literal 0 gemacht. – Rakurai

Antwort

6

Ein Ansatz:

einen Konstruktor hinzufügen, die void* nimmt.

Da literal 0 implizit umwandelbar in einen void* Null-Zeiger, und literal 1 isn `t, wird dies das gewünschte Verhalten angegeben geben. Zur Sicherheit können Sie behaupten, dass der Zeiger im ctor null ist.

Ein Nachteil ist, dass jetzt Ihre Klasse von allem implizit umwandelbar in void * konstruierbar ist. Einige unerwartete Dinge sind so konvertierbar - zum Beispiel vor C++ 11, std::stringstream war umwandelbar zu void*, im Grunde als ein Hack, weil explicit operator bool noch nicht existiert.

Aber das kann gut in Ihrem Projekt funktionieren, solange Sie sich der möglichen Fallstricke bewusst sind.

Edit:

Eigentlich dachte ich an einen Weg, dies sicherer zu machen. Verwenden Sie anstelle von void* einen Zeiger auf einen privaten Typ.

Es könnte wie folgt aussehen:

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

Die wörtliche 0 Umwandlung wird immer noch funktionieren, und es ist wesentlich schwieriger für einige benutzerdefinierten Typ versehentlich unbeabsichtigt Flags::dummy * zu konvertieren.

Verwandte Themen