I have a function that should return an std::function of the same type as that function. Basically I want something like this:
using RetType = std::function<RetType(void)>;
which obviously will not compile. How do I correctly declare the return type?
You cannot use std::function
that way.
You can roll your own, but it will take some work.
Here is a sketch:
template<class T, class A, class B>
struct sub{using type=T;};
template<class T, class A, class B>
using sub_t=typename sub<T,A,B>::type;
template<class T, class B>
struct sub<T,T,B>{using type=B;};
template<class R,class...Args,class A,class B>
struct sub<R(Args...),A,B>{
using type=sub_t<R,A,B>(sub_t<Args,A,B>...);
};
write the above. It takes a type T
, and if it matches A
it returns B
. Otherwise it returns T
. It also works on function signatures.
We can use this with a 'flag' type in a signature to replace with the type of the function object itself:
struct recurse{}; // flag type
// not needed in C++14:
template<class Sig>
using result_of_t=typename std::result_of<Sig>::type;
template<class Sig>
struct func {
using Sig2=sub_t<Sig,recurse,func>;
using function = std::function<Sig2>;
function impl;
template<class...Ts>
result_of_t<function const&(Ts...)>
operator()(Ts&&...ts)const
{
return impl(std::forward<Ts>(ts)...);
}
};
Then func<recurse()>
is a function object that when called, returns a func<recurse()>
.
Turns out the implementation is as simple as storing a std::function<Sig2>
and calling it. The above code lacks polish -- you'd want constructors, more operators, privacy, etc.
live example
Note that a y-combinator might be useful if you want to avoid having to capture a copy of yourself by reference in order to return *this
in a lambda, as capture by reference implies a limited lifetime (and avoid using shared ptr).
Other work that is useful would be enhancing sub
to handle references-to-A
, or even templates that contain A
as an argument. (the general sub algorithm is not doable in C++, as C++ does not have full meta-template capabilities, but handling every template class currently in std
is easy: they are all pure type templates, or std::array
).
For completeness, you can add this to sub
:
// optional stuff for completeness:
template<class T,class A,class B>
struct sub<T&,A,B>{
using type=sub_t<T,A,B>&;
};
template<class T,class A,class B>
struct sub<T*,A,B>{
using type=sub_t<T,A,B>*;
};
template<template<class...>class Z,class... Ts,class A,class B>
struct sub<Z<Ts...>,A,B>{
using type=Z<sub_t<Ts,A,B>...>;
};
template<template<class,size_t>class Z,class T,size_t n,class A,class B>
struct sub<Z<T,n>,A,B>{
using type=Z<sub_t<T,A,B>,n>;
};
template<class T,size_t n,class A,class B>
struct sub<T[n],A,B>{
using type=sub_t<T,A,B>[n];
};
template<class T,class A,class B>
struct sub<T[],A,B>{
using type=sub_t<T,A,B>[];
};
template<class T,class A,class B>
struct sub<T const,A,B>{
using type=sub_t<T,A,B> const;
};
template<class T,class A,class B>
struct sub<T volatile const,A,B>{
using type=sub_t<T,A,B> volatile const;
};
template<class T,class A,class B>
struct sub<T volatile,A,B>{
using type=sub_t<T,A,B> volatile;
};
And it now works recursively on many templates, on arrays, references, and pointers, and with cv-qualified types. This allows you to write something like:
func< std::vector<recurse>() >
which is a function object whose operator()
returns a func< std::vector<recurse>() >
.
Note that this procedure isn't quite perfect, as if some_template<recurse>
isn't a valid template instantiation, the above won't work. A stranger version that takes potentially applied templates and arguments, does the substitution, then the application, would be required in such cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With