Function that accepts any pointer type - c++

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?

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

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.

Related

Deduction guides for functions as template parameters

We can use std::unique_ptr to hold a pointer allocated with malloc which will be freed appropriately.
However, the resulting std::unique_ptr's size will be 2 pointers, one for the pointer to the object and one for the pointer to the deleter function instead of the usual 1 pointer to object and an implicit delete. As one answer points out this can be avoided by writing a custom Unique_ptr that knows the proper deleter function. This function can be made known using a template parameter to support any deleter function like so:
template <class T, void (*Deleter)(T *)>
struct Unique_ptr {
explicit Unique_ptr(T *t, void (*)(T *))
: t{t} {}
~Unique_ptr() {
Deleter(t);
}
//TODO: add code to make it behave like std::unique_ptr
private:
T *t{};
};
template <class T>
void free(T *t) {
std::free(t);
}
char *some_C_function() {
return (char *)malloc(42);
}
int main() {
Unique_ptr<char, free> p(some_C_function(), free); //fine
Unique_ptr q(some_C_function(), free); //should be fine
//with the right
//deduction guide
}
This would be really nice if we could use deduction guides to not have to specify the template parameters. Unfortunately I can't seem to get the syntax right. These attempts fail to compile:
template <class T, auto Deleter>
Unique_ptr(T *, Deleter)->Unique_ptr<T, Deleter>;
template <class T, void (*Deleter)(T *)>
Unique_ptr(T *, void (*Deleter)(T *))->Unique_ptr<T, Deleter>;
Alternatively one could write Unique_ptr<free> q(some_C_function()); in order to manually specify the function template parameter, but that creates issues with deducing T.
What is the correct deduction guide to make Unique_ptr q(some_C_function(), free); or Unique_ptr<free> q(some_C_function()); compile?
Why write your own unique_ptr? Just use std::unique_ptr with a custom delete pointer. With C++17, that's very straightforward:
template <auto Deleter>
struct func_deleter {
template <class T>
void operator()(T* ptr) const { Deleter(ptr); }
};
template <class T, auto D>
using unique_ptr_deleter = std::unique_ptr<T, func_deleter<D>>;
Or, as Yakk suggests, more generally:
template <auto V>
using constant = std::integral_constant<std::decay_t<decltype(V)>, V>;
template <class T, auto D>
using unique_ptr_deleter = std::unique_ptr<T, constant<V>>;
which gets you to:
unique_ptr_deleter<X, free> ptr(some_c_api());
Sure, you have to actually write X, but you have no space overhead. In order to accomplish the same thing with deduction guides, you'd need to wrap the function deleter in order to lift it to a template parameter:
template <class T, auto D>
Unique_ptr(T*, func_deleter<D>) -> Unique_ptr<T, func_deleter<D> >;
Which would be used like:
Unique_ptr ptr(some_c_api(), func_deleter<free>());
I'm not sure that's necessarily better, and you run into all the same problems that led to the standard not having deduction guides for std::unique_ptr (i.e.: differentiating between pointers and arrays). YMMV.

How can I get the C++ compiler to deduce T indirectly?

My template-fu is rather weak. I have this code:
template<typename T>
void Foo(void(*func)(T*)) { }
void Callback(int* data) { }
int Test()
{
Foo(Callback);
}
...but I'd like something more readable than C's nasty function pointer syntax of void(*func)(T*).
Someone on my team suggested this:
template<typename T>
struct Types
{
typedef void Func(T*);
};
template<typename T>
void Foo2(typename Types<T>::Func* func) {}
void Test2()
{
Foo2(Callback); // could not deduce template argument for 'T'
Foo2<int>(Callback); // ok
}
(I'm still debating whether this is actually more readable, but that's a separate issue.)
How can I help the compiler figure out what T is without needing to explicitly specify it in the caller?
You can extract T from the function type using a traits class.
template<class F>
struct CallbackTraits;
template<class T>
struct CallbackTraits<void(*)(T)>
{
typedef T ArgumentType;
};
Your example can be modified like this:
template<typename F>
void Foo(F func)
{
typedef typename CallbackTraits<F>::ArgumentType T;
}
void Callback(int* data) { }
int Test()
{
Foo(Callback);
}
This technique is used in the boost type-traits library:
http://www.boost.org/doc/libs/1_57_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html
This blog post goes into a bit more detail about the implementation of the technique:
https://functionalcpp.wordpress.com/2013/08/05/function-traits/
Unfortunately this approach hides the information in the signature of Foo about the constraints on the argument passed in. In the above example the argument must be a function of type void(T*).
This alternative syntax does the same as the original example while being slightly more readable:
template<typename T>
void Foo(void func(T*)) { }
Another alternative syntax that may be more readable can be achieved using c++11's alias templates as follows:
template<typename T>
using Identity = T;
template<typename T>
void Foo(Identity<void(T*)> func) { }
Unforunately the latest MSVC fails to compile this, reporting an internal compiler error.
You won't be able to deduce the type based on a nested name: there is no reason why different instantiations of the outer type won't define an identical inner type. You could use a using alias, though:
template <typename T>
using Function = auto (*)(T*) -> void;
template <typename T>
void Foo(Function<T>) {
}
Personally, I would recommend against using any of that, however: in practice it seems much more advisable to actually take a function object which later allows using object with suitable function call operators to be used. For callbacks it is quite common that you'll need to pass in some auxiliary data. That is, you would either use an unconstrained template or one which takes a type-erased type, depending on what you want to do exactly:
template <typename Fun>
void Unconstrained(Fun fun) {
}
template <typename T>
void TypeErased(std::function<void(T*)> fun) {
}
The unconstrained version has the advantage that it can potentially inline the function call but it has the disadvantage that every function object type creates a new instantiation and that the argument types are likely to vary. The type-erased version effectively has to do something like a virtual function call but there is just one instantiation of the function template (per argument type T, of course).
Admittedly, the type-erased version's type won't be deduced from a function pointer (or any other argument which isn't a std::function<void(X*)>), i.e., you may want to have a forwarding function
template <typename T>
void TypeErased(Function<T> fun) {
TypeErased(std::function<void(T)>(fun));
}
In C++98 and C++03 template argument deduction only works with functions (and methods).
I don't think the picture changed in the more recent standards.

How can I use unique_ptr with a more generic deleter?

Consider some function:
template<typename F>
void foo(F f) {
std::unique_ptr<int> p = f();
// do some stuff with p
}
Because unique_ptr decrees a default template argument, default_delete, for D, any function object passed to foo that returns a unique_ptr with a non-default deleter fails to compile. For example,
int x = 3;
foo([&x](){
// use empty deleter
return std::unique_ptr<int>(&x, [](int*){});
});
However, I could see this being potentially useful, and I don't see a direct reason why it shouldn't be possible. Is there a common approach for addressing this?
Edit
The easy fix would be to define foo instead to use the following:
std::unique_ptr<int, std::function<void(int*)>> p = f();
But I'm wondering why this couldn't have been incorporated into the interface for unique_ptr? Is there a reason the class interface couldn't provide this generic attribute? Are there approaches for "wrapping" this kind of thing into a new definition?
For example,
template<typename T>
using Generic_unique_ptr =
std::unique_ptr<
T,
std::function< void(typename std::unique_ptr<T>::element_type*) >
>;
But this seems dangerous because it exposes the potential to do something like the follwing,
Generic_unique_ptr<int> p(new int());
which would leave the deleter uninitialized and exhibit undefined behavior. Perhaps some way to provide an instance of std::default_delete<T> as the default deleter?
If all you want to do is use the pointer in a function, you can just
use the auto keyword; the compiler will deduce the type of unique_ptr
which has been used and thus automatically do the right thing:
template <typename F>
void foo(F f)
{
auto p = f();
p->bar();
}
Now, from your comment, we know that this is not all you want, but you
want to be able to store the unique_ptr in your class to work with
it later. This creates a set of completely different problems:
unique_ptr<T, D1> and unique_ptr<T, D2> are different types. Thus we need to know what unique_ptr<T, D> will be returned by your functor F
Even if we knew the return type of F in advance, our class can still only store unique_ptr<T, D1> and not unique_ptr<T, D2>.
The easiest way around this (that I can think of, there might be better
ways) is type erasure.
We create ourselves a base class that exposes the pointer managed by the
unique_ptr:
template <typename T>
struct wrapper
{
virtual ~wrapper() {}
virtual T const * get() const = 0;
virtual T * get() = 0;
};
From that class inherits our actual storage class, which deduces the type
of unique_ptr:
template <typename T, typename F>
struct storage
: wrapper<T>
{
storage(F f) { p_ = f(); }
T const * get() const { return p_.get(); }
T * get() { return p_.get(); }
private:
typename std::result_of<F()>::type p_;
};
In the class you actually care about, you can now store a pointer to our
base class and use polymorphism to access the underlying object, in this
case the unique_ptr. Assume we moved the classes above into
namespace detail to hide them from the user:
template <typename T>
class some_class
{
public:
template <typename F>
void store(F f)
{
storage_.reset(new detail::storage<T, F>(f));
}
T const * get() const { return storage_->get(); }
T * get() { return storage_->get(); }
private:
std::unique_ptr<detail::wrapper<T>> storage_;
};
You can find a fully working example here.
But I'm wondering why this couldn't have been incorporated into the interface for unique_ptr?
Because to do so would force all of std::function's overhead onto everyone. unique_ptr is intended to be useful for pretty much any case of single ownership of a pointer. You pay for what you use; not everyone who uses a custom deleter needs that deleter to be generic. This way, they don't have to pay for it.
Also, the current methodology allows it to handle non-pointer resources, as the deleter can specify exactly what type gets stored in the unique_ptr.
If you want to provide this generic deleter construct, you could create a class that (privately) inherits from unique_ptr and replicates its interface, minus the constructor that doesn't take a deleter instance. That way, the user is forced to pass a deleter function in.

Changing deleter for std::unique_ptr

I want to change default_deleter for std::unique_ptr. This is quite easy to achieve, but there is one inconvenient - I have to declare variables using 2 template parameters instead of one, something like this:
std::unique_ptr<MyType, MyDeleter<MyType>> myVar;
As you may see the declaration is long and I have a feeling I can use a shorter version, but I don't know how:)
Is it possible to declare some kind of MyUniquePtr<T> that will be the same as std::unique_ptr<T, MyDeleter<T>>?
EDIT: Matthieu M. already answered, but unfortunately I can't use this feature in Visual Studio as it's not implemented. Is there other way to have this behavior?
Actually it is, using template aliases:
template <typename T>
using MyUniquePtr = std::unique_ptr<T, MyDeleter<T>>;
If your compiler doesn't do template aliases yet, here's the C++03 idiom:
template <typename T>
struct MyUniquePtr {
typedef std::unique_ptr<T, MyDeleter<T> > type;
};
MyUniquePtr<MyType>::type var;
The setup is uglier, but the resulting usage is almost as short: you just need to add ::type.
Does your deleter need to be templated on the type of the object being deleted, or is it sufficient for the function call operator to be templated on the type of object being deleted?
Instead of:
template<typename T>
struct MyDeleter
{
void operator()(T* p) const { /* ... */ }
};
Can you write:
struct MyDeleter
{
template<typename T>
void operator()(T* p) const { /* ... */ }
};
This, of course, depends on what state MyDeleter has to maintain.
Another way conforming to c++03 is a subclass, which unfortunately requires you to reproduce the constructors. (This can be done easier, if your compiler supports variadic template arguments, which may be the case for current MSVC.)
template <class T>
class MyUniquePtr : public std::unique_ptr< T, MyDeleter<T> > {
public:
MyUniquePtr(args...) : std::unique_ptr< T, MyDeleter<T> >(args...) { }
};
You might want to consider writing your own version of a make_unique style function instead specialized for your custom allocation / deletion strategy. This also has the advantage that you can perform any specialized resource acquisition / allocation in an exception safe way. You can then declare your unique_ptr as auto and let type deduction work for you.

Template parameters in C++

Suppose I have arbitrary template method, which could receive parameters by value and by const reference (obviously, for trivial types and for objects accordingly).
How is this situation handled when writing template function prototypes?
I could make something like:
template <typename T> void Foo(T value) {
// Do something.
}
template <typename T> void Foo(const T& value) {
// Do something, yeah.
}
// Specialization for first prototype.
template <> void Foo<int>(int value) { }
// Specialization for second prototype.
template <> void Foo<Object>(const Object& value) { }
But this approach is only okay for trivial functions, that act purely as a wrapper for some other calls.
If the function (non-templated version) has a lot of code inside it, this means I would have to copy the code twice.
Can I make something smarter here?
Just take by const reference ALWAYS, because there isn't much overhead in passing primitive types as const references.
Write your template code for const references only and rely on the compiler to optimize the references away.