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?
CodePudding user response:
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);
CodePudding user response:
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.