In C++, I want to have a class whose constructors are the following:
class A {
explicit A(A* other) { ... }
explicit A(intptr_t other) { ... }
};
The problem with this is if the user initialize with
A a(0);
Then, on a 64 bits system, the compiler will complain that it doesn't know if 0
should be converted to A*
or to intptr_t
, which is fair enough. As I want this simple notation to work, I added the following constructor:
explicit A(int a) { assert(a==0); ... }
The assertion is because this is the only integer this makes sense for. Now, the problem arises with a 32 bits system, in which intptr_t
is actually ... int
! So now, the system complains there are two constructors taking the same parameter type (which, again, is fair enough).
So my question is: is there a way with the preprocessor to detect that intptr_t
is actually int
and, in that case, not compile the constructor with int
. Or, is there another way to make the A a(0)
notation valid without adding the constructor with int
, but without removing either of the two first constructor (and not making them implicit either).
Something like
#if INTPTR_MAX == INT_MAX
might do the trick, but it will still result in true where long
and
int
are the same size, and ptrint_t
is a typedef for long
.
Another possibility (but don't know whether you can use it or not)
would be to use uintptr_t
, rather than intptr_t
.
Beyond these: the preprocessor doesn't know about types, so the problem
can't be solved there. You'll have to use some sort of meta-programming
trick: you make the int
constructor a template, using
boost::enable_if
to activate it only if the argument has type int
.
If ptrint_t
is int
, then the activated function will never be
used, because it will never be a better match than the non-template
function with the same signature. If ptrint_t
isn't int
, then the
template instantiation will be a better match when the argument has type
int
. (Note that I've never tried this myself: it sounds to me like it
should be possible, but I'm not that familiar with boost::enable_if
to
be sure.)
Why don't you simple implemment a parameterless constructor that acts as if other
were 0
? If, for some reason you don't want to, I suggest using type traits, provided you have access to C++11 compiler or boost:
class A {
public:
explicit A(A* other) { ... }
explicit A(intptr_t other) { ... }
template <class T>
explicit A(T other)
{
static_assert(std::is_convertible<T, intptr_t>::value, "Could not convert value to intptr_t");
static_assert(std::is_integral<T>::value, "Argument must be integral");
intptr_t p = other;
...
}
};
You can get rid of static assertions and type checkings, but then instead of compiler error you would get a warning (depending on your warning level, may even be turned into an error) when you do the following:
A a(0.0f);
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