Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if a type is a typedef of int

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).

like image 297
PierreBdR Avatar asked Nov 04 '22 09:11

PierreBdR


2 Answers

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.)

like image 62
James Kanze Avatar answered Nov 09 '22 10:11

James Kanze


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);
like image 44
gwiazdorrr Avatar answered Nov 09 '22 08:11

gwiazdorrr