在 C++ 中防止整数 0 隐式转换为指针的最佳方法是什么

joh*_*ash 5 c++ implicit-conversion explicit-conversion c++11 visual-studio-2013

我试图找出防止整数 0 隐式转换为 nullptr_t 然后传递给采用指针的构造函数的最佳方法。显式不会这样做,但我可以获得 nullptr_t 来导致不明确的重载错误:

#include <typeinfo.h>

struct A {
    explicit A(char*) { }
};

struct B {
    B(nullptr_t a) = delete;
    B(char*) { }
};

int main(int argc, char* argv[])
{
    A a(0);         // darnit I compiled...
    B b1(0);        // good, fails, but with only b/c ambiguous
    B b2((char*)0); // good, succeeds
    B b3(1);        // good, fails, with correct error
}
Run Code Online (Sandbox Code Playgroud)

还有比这更好的方法吗?另外,删除在这里到底要完成什么?

Mik*_*han 2

删除A(int)不会阻止A(char *)被调用 nullptrA(nullptr_t)所以你也需要删除。

即使这样也不能保护您免于出现这样的情况:附近有一些流氓类可以从 0 或 隐式构造nullptr,并将其隐式转换为char *

#include <iostream>

struct A {
    A(int) = delete;
    A(std::nullptr_t) = delete;
    explicit A(char * p) {
        std::cout << "Constructed with p = " << (void *)p << std::endl;
    }
};

struct X
{
    X(long i) : _i(i) {}
    operator char *() const { return (char *)_i; }
    long _i;
};

int main()
{
    X x(0);
    A a(x);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

程序打印:

Constructed with p = 0
Run Code Online (Sandbox Code Playgroud)

你可能认为这种可能性微乎其微,可以忽略不计。或者您可能更愿意一次性删除所有构造函数,其参数不完全属于您认可的类型。例如,假设认可的类型只是char *

struct A {
    template<typename T>
    A(T) = delete;
    explicit A(char * p) {}
};

struct X
{
    X(long i) : _i(i) {}
    operator char *() const { return (char *)_i; }
    long _i;
};

int main()
{
    // A a0(0);
    //A a1(nullptr);
    X x(0);
    // A a2(x);
    char *p = x;
    A a3(p); // OK     
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这里所有注释掉的构造函数调用都无法编译。