2014-08-28 16 views
5

Mam następujący kod z klasy zwyczaj wariant i niestandardową SmartPtr Klasa:automatyczna konwersja bool do nullptr_t

using namespace std; 

class Object 
{ 
public: 
}; 

template<typename T> 
class SmartPtr 
{ 
public: 

    template<typename Y> 
    explicit SmartPtr(Y* p) { p_ = p; } 

    SmartPtr(std::nullptr_t) { p_ = nullptr; } 

private: 
    T* p_; 
}; 

class Variant 
{ 
public: 
    Variant(bool b) : _b(b) { } 

private: 
    bool _b; 
}; 

class Obj 
{ 
public: 
    void test(SmartPtr<Object> /*p*/) { cout << "smartptr version!" << endl; } 
    void test(Variant /*v*/) { cout << "variant version!" << endl; } 
}; 

int main(int argc, const char *argv[]) 
{ 
    Obj o; 
    o.test(nullptr); // calls SmartPtr version 
    o.test(true); // calls Variant version 
    o.test(false); // -> compiler error: ambiguous call to overloaded function 

    return 0; 
} 

Zakładam, że logiczna fałsz można przekształcić zarówno do wariantu i 0 następnie nullptr, a następnie SmartPtr, który powoduje ten błąd.

Jakieś szanse na uniknięcie tej konwersji?

Dla użytkownika biblioteki interfejs API współpracujący z "o.test (true);" ale wymaga czegoś takiego jak "o.test (Variant (false))" do kompilacji nie jest bardzo intuicyjny.

+0

Różne kompilatory traktują ten kod w różny sposób. g ++ (C++ 1y) kończy się niepowodzeniem zarówno po 'nullptr', jak i' false'. clang (C++ 1y) nie działa w 'nullptr'. Powiązane pytanie: http://stackoverflow.com/questions/17501942/false-implicitly-convert-to-null-pointer/ – zch

+0

Myślę, że standardowy zgodny kompilator powinien akceptować cały kod ('nullptr_t -> SmartPtr' jest lepszy niż' nullptr_t -> bool -> Variant' i 'bool -> nullptr_t -> SmartPtr' jest nieprawidłowy), ale myślę, że to nie pomoże ci. Polecam używanie osobnych nazw funkcji. – zch

+0

@zsh: Używam zarówno clang i g ++ z std = C++ 11 na linuxie, jak i vc12 na windows, komunikat o błędzie jest taki sam. Niestety, inna nazwa nie wchodzi w grę, ponieważ kod pracował wcześniej i próbuję wprowadzić konstruktor nullptr_t dla klasy SmartPtr, która powoduje, że kompilacja się nie udała. – mgr

Odpowiedz

1

Uważam, że mam idealne rozwiązanie. Wymaga jedynie zmiany funkcji testu, więc pozostawia SmartPtr i Wariant sam, co jest idealne. Dodaje nieprzedefiniowane przeciążenie szablonowe w celu przetestowania, które ma zdefiniowane specjalizacje dla wartości bool i nullptr. Spowoduje to bezpośrednie wywołanie wartości bool i nullptr do wybranej specjalizacji, ale spowoduje błędy w łączach na innych nieobsługiwanych typach. Tak się cieszę, że to się udało, ponieważ sam z pewnością wpadłem na to w wielu postaciach. Szkoda, że ​​nie możesz użyć jawnych parametrów funkcji !!

mam pojęcia, stąd: C++ templates that accept only certain types

using namespace std; 

class Object 
{ 
public: 
}; 

class Variant 
{ 
public: 
    Variant(bool b) : _b(b) { } 

private: 
    bool _b; 
}; 

template<typename T> 
class SmartPtr 
{ 
public: 
    SmartPtr(std::nullptr_t null) { p_ = nullptr; } 

    template<typename Y> 
    SmartPtr(Y* p) { p_ = p; } 

private: 
    T* p_; 
}; 

class Obj 
{ 
public: 
    void test(SmartPtr<Object> here /*p*/) { 
     cout << "smartptr version!" << endl; 
    } 
    void test(Variant /*v*/) { cout << "variant version!" << endl; } 

    template<typename T> void test(T t); 

    template<> 
    void test<bool>(bool b) { 
     cout << "bool specialization" << endl; 
     test(Variant(b)); 
    } 

    template<> 
    void test<std::nullptr_t>(std::nullptr_t null) { 
     cout << "nullptr specialization" << endl; 
     test(SmartPtr<Object>(nullptr)); 
    } 
}; 

int main(int argc, const char *argv[]) 
{ 
    Obj o; 
    Obj c; 
    Object object; 

    //o.test(3); // Gives link error LNK2019 

    o.test(Variant(true)); // calls Variant version 
    o.test(SmartPtr<Object>(&object)); // calls SmartPtr version 
    o.test(nullptr); // dispatched to SmartPtr version by nullptr specialization 
    o.test(true); // dispatched to Variant version by bool specialization 
    o.test(false); // dispatched to Variant version by bool specialization 
    return 0; 
} 

ja już odpowiedział coś nie jest idealny, więc zostawiam tę odpowiedź w takt jak co następuje:

======= ======================================

Nie mam idealnego rozwiązania tutaj, i nie znam ograniczeń na twoim kodzie, więc może to nie być użyteczne dla ciebie, ale poniższe jest sensowne. Uniemożliwia to użycie kodu nullptr w czasie kompilacji i opiera się na globalnej stałej null_smart, która ma być używana we wszystkich przypadkach, gdy wywołujący po prostu nie wykazuje zainteresowania przekazywaniem obiektu.

#include <iostream> 

using namespace std; 

class Object 
{ 
public: 
}; 

class Variant 
{ 
public: 
    Variant(bool b) : _b(b) { } 
private: 
    Variant(std::nullptr_t) {}; 

private: 
    bool _b; 
}; 

template<typename T> 
class SmartPtr 
{ 
public: 
    SmartPtr() { p_ = nullptr; } 

    template<typename Y> 
    SmartPtr(Y* p) { p_ = p; } 

private: 
    T* p_; 
}; 

class Obj 
{ 
public: 
    void test(SmartPtr<Object> /*p*/) { cout << "smartptr version!" << endl; } 
    void test(Variant /*v*/) { cout << "variant version!" << endl; } 
}; 

const SmartPtr<Object> null_smart; 

int main(int argc, const char *argv[]) 
{ 
    Obj o; 
    o.test(null_smart); // calls SmartPtr version, without interest in passing object 
    o.test(true); // calls Variant version 
    o.test(false); // calls Variant version 
    return 0; 
} 

Jest czystszy niż prawdziwy/wariantowy (fałszywy), ale wciąż jest nieco bardziej wybredny.

+0

Obiekt z metodą test() znajduje się w kodzie użytkownika, który istniał przed moim pomysłem, aby mieć jednolitą składnię pustego wskaźnika dla wszystkich surowych i niestandardowych klas SmartPtr. – mgr

Powiązane problemy