2017-06-13 11 views
5

Mam klasę Flags, która zachowuje się podobnie do std::bitset, która zastępuje bitowe liczby całkowite w starszej bazie kodu. Aby wymusić zgodność z nowszą klasą, chcę zabronić niejawnej konwersji z typów int.Zezwalanie na niejawną konwersję dla pojedynczej wartości

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

Chciałbym umożliwić niejawnego budowę i przypisanie tylko z Flag i Flags typów. Chciałbym jednak jeszcze jak kilka wywołań funkcji, które mają parametr Flags zaakceptować dosłownego 0, lecz nie inne liczby całkowite:

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 

to jest możliwe? Aby umożliwić niejawną konwersję 0 podczas blokowania innych wartości?

+0

Dlaczego w tym miejscu jest specjalne "0"? – tadman

+1

Możesz dodać konstruktora pobierającego void *, który zostanie wywołany przez 0. Następnie upewnij się, że wskaźnik ma wartość null w ctor. To pierwsza rzecz, która przychodzi do głowy, być może jest to czystszy sposób. Literał 1 nie będzie konwertować niejawnie na pustkę * –

+0

@tadman W wywołaniach funkcji, które pobierają bitową liczbę całkowitą, nie przekazuje ona żadnych bitów. W mojej bazie kodu istnieje wiele wywołań funkcji, w których wektor bitowy zawiera opcjonalne parametry, i wiele razy wywołanie jest wykonywane za pomocą dosłownego 0. – Rakurai

Odpowiedz

6

Jedno podejście:

Dodaj konstruktora, który trwa void*.

Od dosłownym 0 jest niejawnie przekształcić w void* zerowego wskaźnika i dosłownym 1 isn`t, to daje pożądanego zachowania wskazanego. Dla bezpieczeństwa możesz stwierdzić, że wskaźnik jest zerowy w ctor.

Wadą jest to, że teraz twoja klasa jest konstruktywna z niczego niejawnie wymienialnego na void *. Niektóre nieoczekiwane rzeczy są tak wymienialne - na przykład przed C++ 11, std::stringstream można było zamienić na void*, w zasadzie jako włamanie, ponieważ explicit operator bool jeszcze nie istniało.

Ale to może się udać w twoim projekcie, o ile wiesz o potencjalnych pułapkach.

Edit:

Właściwie Pamiętałem sposób, aby to bezpieczniejsze. Zamiast void* użyj wskaźnika do typu prywatnego.

To może wyglądać następująco:

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

Dosłowne 0 konwersja będzie nadal działać, a to znacznie trudniejsze dla niektórych typ zdefiniowany przez użytkownika przypadkowo konwertować do Flags::dummy * nieumyślnie.

Powiązane problemy