bool自动转换为nullptr_t

时间:2014-08-28 12:44:42

标签: c++ c++11

我有以下代码,其中包含自定义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));'编译不是很直观。

1 个答案:

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

它比真正/变异(假)问题更清晰,但仍然有点挑剔。