PierreBdR
PierreBdR

Reputation: 43244

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

Upvotes: 5

Views: 588

Answers (5)

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 506915

I suppose the simplest thing is to declare all 6 constructors (int, long, long long, and their unsigned variants), instead of using intptr_t.

Upvotes: 0

BЈовић
BЈовић

Reputation: 64223

You can also pass a parameter, which determines which one is called :

struct TakePtr{};
struct TakeInt{};

class A {
  A(A* other, const TakePtr&) { ... }
  A(intptr_t other, const TakeInt&) { ... }
};

This way you can make sure which constructor is called :

A a2( 0, TakeInt() );     // calls the 2nd constructor, taking int
A a1( &a2, TakePtr() );   // calls the 1st constructor, taking a pointer

Upvotes: -1

gwiazdorrr
gwiazdorrr

Reputation: 6329

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

Upvotes: 1

iammilind
iammilind

Reputation: 69988

is there another way to make the A a(0) notation valid

Just introduce a template constructor.

class A {
public:
  template<typename T>
  explicit  A (T t) { assert(t==0); }  // explicit matters ?

  explicit A(A* other) { ... }
  explicit A(intptr_t other) { ... }
};

This will solve your 32-bit and 64-bit problem!

Upvotes: -1

James Kanze
James Kanze

Reputation: 153909

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

Upvotes: 3

Related Questions