我有以下代码,其中包含自定义Variant类和自定义SmartPtr类:
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;
}
我假设布尔值false可以转换为Variant,然后转换为0然后转换为nullptr,然后转换为SmartPtr,这会导致此错误。
是否有机会避免这种转变?
对于库的用户,使用'o.test(true);'的API但要求'o.test(Variant(false));'编译不是很直观。
答案 0 :(得分:1)
我相信我有一个理想的解决方案。它只需要改变测试功能,因此它只留下SmartPtr和Variant,这是理想的。它为测试添加了一个未定义的模板化重载,它具有已定义的bool和nullptr的特化。这会直接将bool和nullptr调度到所需的特化,但会导致其他未处理类型的链接错误。我很高兴能够解决这个问题,因为我自己确实以多种形式遇到过这个问题。我希望你能使用明确的函数参数!!
我从这里得到了这个想法: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;
}
我已经回答了一些不理想的事情,所以我将这个答案留下来,如下所示:
=============================================
我在这里没有理想的解决方案,而且我不知道您对代码的限制,所以这对您来说可能没有用处,但以下是明智的。它不允许代码在编译时使用nullptr并依赖于一个全局null_smart常量,以便在调用者只是对传递对象没有兴趣的所有情况下使用它。
#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;
}
它比真正/变异(假)问题更清晰,但仍然有点挑剔。