edit Possibly can\'t be done, see Clean implementation of function template taking function pointer although answer 1 there has a C macro work-around https://stacko
I think for c++11 it is impossible to achieve what you want.
template<typename T, typename D> class unique_gptr : public std::unique_ptr<T, decltype(&D)> { public: unique_gptr(T* t) : std::unique_ptr<T, decltype(&D)>(t, D) { }; }; using int_gptr = unique_gptr<int, ::free_int>; int_gptr ig(new int(2));
Notice that decltype
is applied on D
, which is declared as a typename
. So D
is a type. But decltype
can't be used on a type.
Firstly the code tries to get the address of a type (&
). Secondly, the argument of decltype
is expected to be an expression, but not a type or "the address of a type". To make it easier to understand, we can say that decltype
expects its argument to be a “variable”, like the following example.
int main()
{
int i = 10;
decltype(i) j;
decltype(int) k; /* Compiler error. */
decltype(&int) l; /* Compiler error. */
return 0;
}
You also want the compiler to replace D
with ::free_int
. And ::free_int
is passed in as a non-type template argument. However D
is a type template parameter. A non-type template parameter starts with an actual type (e.g. int
, struct a*
or a type template name). While a type template parameter starts with typename
or class
. An easier example for non-type template parameter,
template<int INIT>
void func2(void)
{
decltype(INIT) j = INIT;
}
int main()
{
func2<10>();
return 0;
}
When you pass in a function pointer like ::free_int
, you need a non-type template parameter, which must be preceded by a type. And you want the type of the function pointer to be "replaceable". So the type of the function pointer has to be a type template parameter. These make them two template parameters.
That's the reason you need three template parameters in template<typename T, typename D, D F>
, which is the best result you have.
You can use some macro magic:
template<class T, class D, D d>
struct UniqueDeleter : public std::unique_ptr<T, D> {
UniqueDeleter(T* t) : std::unique_ptr<T, D>(t, d) { };
};
template<class R, class T>
T decl_unique_deleter_ptr(R (*d)(T*));
#define DECL_UNIQUE_DELETER1(f) UniqueDeleter<decltype(decl_unique_deleter_ptr(&f)), decltype(&f), &f>
#define DECL_UNIQUE_DELETER2(T, f) UniqueDeleter<T, decltype(&f), &f>
#define DECL_UNIQUE_DELETER_GET_MACRO(_1, _2, NAME, ...) NAME
#define DECL_UNIQUE_DELETER_EXPAND(x) x
#define decl_unique_deleter(...) DECL_UNIQUE_DELETER_EXPAND(DECL_UNIQUE_DELETER_GET_MACRO( \
__VA_ARGS__, DECL_UNIQUE_DELETER2, DECL_UNIQUE_DELETER1, _)(__VA_ARGS__))
Now you can use it like such:
decl_unique_deleter(int, free_int) ig(new int(2));
Or with using
and some more magic:
using int_gptr = decl_unique_deleter(free_int); // If accepted pointer type matches.
int_gptr ig(new int(2));
I might also recommend an alternative solution:
auto i = new int(2);
BOOST_SCOPE_EXIT_ALL(&) { delete i; };
You cannot use decltype
with a type as the goal is to obtain the type of a variable. But in decltype(&D)
, D
is a type.
I would rather pass throught a template function:
template<typename T, typename D, D F>
class unique_gptr : public std::unique_ptr<T, D> {
public: unique_gptr(T* t) : std::unique_ptr<T, D>(t, F) { };
};
template <typename T, typename D>
unique_gptr<T, D F> make_unique_gptr(T pointer, D deleter)
{
return unique_gptr<T, D, deleter>(pointer);
}
auto ptr = make_unique(new int(2), ::free_int);