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.
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
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
@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