Benjy Kessler
Benjy Kessler

Reputation: 7656

Function that accepts any pointer type

I have a function void Foo(MyType* mt). I want callers to be able to pass any pointer type to this function (e.g. unique_ptr, shared_ptr or iterator) and not require passing a raw pointer. Is there any way to express this? I could write:

template <typename T>
void Foo(T t);

This will work since it will only compile if T supports operator-> and operator* which I use inside Foo, it will also only work if T has the same interface as MyType but it seems wrong to not specify in the API that I expect that template argument to be a pointer to MyType. I could also write my own wrapper:

template <typename T>
class PointerWrapper {
 public:
  PointerWrapper(T* t) : raw_ptr(t) {}
  PointerWrapper(const std::unique_ptr<T>& t) : raw_ptr(t.get()) {}
  ...
 private:
  T* raw_ptr;
};

void Foo(PointerWrapper<MyType> mt);

This seems clunky because I will need to extend PointerWrapper for every smart pointer type under the sun.

Is there an accepted way to support this?

Upvotes: 4

Views: 458

Answers (2)

n. m. could be an AI
n. m. could be an AI

Reputation: 120011

I want callers to be able to pass any pointer type to this function (e.g. unique_ptr, shared_ptr or iterator

Don't.

Each kind of smart (or dumb) pointer has a very specific purpose, illustrated below.

void foo(std::shared_ptr<T>);  // I will assume joint ownership 
                               // that may or may not outlive the call

void foo(std::unique_ptr<T>);  // I will take your ownership away
                               // You better not be needing it anymore

void foo(T*);                  // I am just borrowing it
                               // Whoever owns it should not worry

It makes little sense for a function to either take ownership or not, depending on what kind of pointer the user passes.

And, naturally, if your function does not do any iterating things, it should not take iterators.

Upvotes: 3

Caleth
Caleth

Reputation: 63019

In C++20, you'd write a concept such as

template <typename P, typename T>
concept points_to = requires(P p) {
    { *p } -> std::common_reference_with<T &>
} && std::equality_comparable_with<std::nullptr_t>

template <points_to<MyType> T>
void Foo(T t);

Prior to that, you could write something involving std::pointer_traits

template <typename T>
std::enable_if_t<std::is_same_v<MyType, typename std::pointer_traits<T>::element_type>> Foo(T t);

Upvotes: 9

Related Questions