2014-08-28 52 views
5

我有一个自定义的变体类下面的代码和一个自定义的SmartPtr类:布尔的自动转换为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; 
} 

我假定布尔假可以既转换为变体和0,则至nullptr,然后到SmartPtr,这会导致此错误。

有没有可能避免这种转换?

对于图书馆的用户来说,使用'o.test(true)'的API;'但需要像'o.test(Variant(false))';'编译并不是很直观。

+0

不同的编译器对待这段代码的方式不同。 g ++(C++ 1y)在'nullptr'和'false'都失败。 clang(C++ 1y)在'nullptr'失败。相关问题:http://stackoverflow.com/questions/17501942/false-implicitly-convert-to-null-pointer/ – zch 2014-08-28 12:56:08

+0

我认为符合标准的编译器应该接受整个代码('nullptr_t - > SmartPtr'优于'nullptr_t - > bool - > Variant和'bool - > nullptr_t - > SmartPtr'无效),但我想这对你没有多大帮助。我会建议使用单独的函数名称。 – zch 2014-08-28 13:24:21

+0

@zsh:我在linux上使用clang和g ++以及std = C++ 11以及windows上的vc12,错误消息也是一样的。不幸的是,不同的命名是不成问题的,因为之前的代码工作正常,我尝试为SmartPtr类引入nullptr_t构造函数,从而导致编译失败。 – mgr 2014-08-29 07:20:50

回答

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

它比真/变异(错误)问题更清洁,但在挑剔的一面仍然有点。

+0

带有test()方法的对象位于用户代码中,该用户代码在我的想法之前就已存在,用于为所有原始和自定义SmartPtr类使用统一的空指针语法。 – mgr 2014-09-01 11:30:11