Is it possible to write a class such that these are valid:
Foo a;
Foo b = 0;
Foo c = b;
Foo d(0);
Foo e(1);
Foo f = Foo(1);
But these are not:
int x;
Foo a = x;
Foo b = 1;
Foo c = 2;
//etc
Essentially, my rule is "A constant 0
is implicitly convertible to a Foo
, but no other value is"
If you don't mind Foo b = nullptr;
working, it's pretty easy to hack up. Have an explicit constructor from int
, and an implicit from std::nullptr_t
.
If you do mind that working, I'm not sure it's possible. The only way to distinguish between a literal 0
and other integer literals is the former's implicit conversion to pointers and nullptr_t
. So nullptr
will prefer a nullptr_t
parameter to a pointer parameter, so by having both constructors you could filter out nullptr
arguments. However, the conversions of 0
to pointers and nullptr_t
are of the same rank, so this would kill 0
arguments with an ambiguity.
Hmm ... something like this may work:
class Foo {
struct dummy;
public:
explicit Foo(int); // the version that allows Foo x(1);
Foo(dummy*); // the version that allows Foo x = 0;
template <typename T,
typename = typename std::enable_if<
std::is_same<T, std::nullptr_t>::value>::type>
Foo(T) = delete; // the version that prevents Foo x = nullptr;
};
I haven't actually tried this. In theory, the template should only participate in overload resolution when the argument is nullptr
, because otherwise SFINAE kills it. In that case, however, it should be better than the pointer constructor.
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