Apollys supports Monica
Apollys supports Monica

Reputation: 3258

C++ General Pointer Function or Template

How can I write a function that would be compatible either with vanilla pointer types (T*) or the special pointer types defined in <memory> such as std::unique_ptr?

I tried using the std::is_pointer check, but it looks like this is not the correct approach:

#include <iostream>
#include <memory>

template<typename T>
void SomePointerFunction(
     T p, typename std::enable_if<std::is_pointer<T>::value>::type* = nullptr) {
  std::cout << (p ? "not null" : "null") << std::endl;
}

int main() {
  int* p;
  std::unique_ptr<int> q;
  SomePointerFunction(p); // If we cange p to q, template matching fails

  return 0;
}

Is there some sort of general pointer type defined in C++ that could encapsulate these different types of pointers, or a different template check that would achieve this?


After thinking about it more, I also understand why this would actually be an undesirable feature of the language, because the two types of pointers are very different in many ways. However, if you just want to write a function that utilizes the dereferencing property of pointers, it seems reasonable that this could be useful. Is there some way to say "This function takes one argument, for which the operator * is defined"?

Upvotes: 2

Views: 117

Answers (1)

tkausl
tkausl

Reputation: 14279

Is there some way to say "This function takes one argument, for which the operator * is defined"?

There is, just try to dereference it. If it doesn't work, SFINAE kicks in:

template<typename T, typename = decltype(*std::declval<T>())>

We're using std::declval to get a T, dereference it and try to get the decltype. The end-result is ignored, we only need it to compile, which means T is dereferencable.

#include <iostream>
#include <memory>

template<typename T, typename = decltype(*std::declval<T>())>
void SomePointerFunction(
     T& p) {
  std::cout << (p ? "not null" : "null") << std::endl;
}

int main() {
  int* p = nullptr;
  std::unique_ptr<int> q;
  int i = 0;
  SomePointerFunction(p);
  SomePointerFunction(q);
  //SomePointerFunction(i);
  /* Above prints:
   main.cpp: In function 'int main()':
   main.cpp:16:24: error: no matching function for call to 'SomePointerFunction(int&)'
   */

  return 0;
}

Upvotes: 5

Related Questions