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