简体   繁体   中英

How can I use static polymorphism to convert between int and pointer types?

I have this piece of code:

#include <iostream>

template<class T> void* ToPtr(T t) { return ToPtr((void*)t); }
void* ToPtr(void* i) { return i; }
void* ToPtr(int i) { return (void*)(long)(unsigned int)i; }

template<class T> int ToInt(T t) { return ToInt((void*)t); }
int ToInt(void* i) { return (int)(unsigned int)(long)i; }
int ToInt(int i) { return i; }

struct MyClass {
  template<class T>
  void* Find(T t) { return ToPtr(t); }

  template<class T>
  int FindInt(T t) { return ToInt(t); }
};

int main() {
  MyClass myClass;
  int myInt = 1;
  std::cout << &myClass << std::endl;
  std::cout << myInt << std::endl;
  std::cout << myClass.Find(&myClass) << std::endl;
  std::cout << myClass.Find(myInt) << std::endl;
  std::cout << myClass.FindInt(&myClass) << std::endl;
  std::cout << myClass.FindInt(myInt) << std::endl;
}

The program crashes in the first call to Find() but I'm not sure why. I'm using GCC 6.2.0, which is only C++14 compliant, otherwise I'd use constexpr. What am I doing wrong?

template<class T> void* ToPtr(T t) { return ToPtr((void*)t); }

This calls itself. Forever.

Since non-templates are preferred over templates, this is really easy to fix: you just have to put the non-templates first so that they're in scope within the overload above:

void* ToPtr(void* i) { return i; }
void* ToPtr(int i) { return (void*)(long)(unsigned int)i; }
template<class T> void* ToPtr(T t) { return ToPtr((void*)t); }

int ToInt(void* i) { return (int)(unsigned int)(long)i; }
int ToInt(int i) { return i; }
template<class T> int ToInt(T t) { return ToInt((void*)t); }

( live demo )

When your program "crashes", you should be running it in a debugger. You'd have seen the stack overflow quite clearly, as hundreds of stack frames would all show the same recursive call.

This function

template<class T> void* ToPtr(T t) { return ToPtr((void*)t); }

calls itself indefinitely…

ToPtr is not a dependent name inside this function template (because a cast to void* is never a type-dependent expression [temp.dep.expr]/3 ), thus, it is looked up at the point of definition of the function template, not at the point of instantiation. Since none of the other overloads of ToPtr are declared at the point of definition, the function template ends up calling itself. Make sure that all overloads of ToPtr are declared before the definition of your function template…

Apart from that, you should really never convert pointers to unsigned int or int as these types are not guaranteed to be large enough to actually represent a pointer value. Use std::uintptr_t or std::intptr_t for that if you really must do it…

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM