I am trying to figure out the best way to prevent integer 0 from being implicitly cast to nullptr_t and then passed to constructors that take pointers. Explicit doesn't do it, but I can get nullptr_t to cause an ambiguous overload error:
#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
}
Is there a better way than this? Also, what exactly is delete accomplishing here?
Deleting A(int)
will not prevent A(char *)
being called with
nullptr
. So you will need to delete A(nullptr_t)
as well.
And even this will not protect you from the eventuality that
there is some rogue class in the neighbourhood that is
implicitly constructible from 0 or nullptr
and
implicitly converts same to 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;
}
The program prints:
Constructed with p = 0
You may reckon that possibility remote enough to be ignored;
or you might prefer to delete all constructors,
in one fell swoop, whose argument is not precisely of a type
that you sanction. E.g. assuming the sanctioned types are just 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;
}
Here all of the commented out constructor calls fail to compile.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With