The return type of the function that returns the std :: function

I have a function that should return a std :: function of the same type as this function. Basically I want something like this:

using RetType = std::function<RetType(void)>; 

which obviously will not compile. How to declare a return type correctly?

+5
source share
1 answer

You cannot use std::function in this way.

You can roll on 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 above. It takes type T , and if it matches A , it returns B Otherwise, it returns T It also works with feature signatures.

We can use this with the type 'flag' in a signature that replaces 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()> .

Turning off an implementation is as simple as std::function<Sig2> and calling it. There is no polishing in the above code - you need constructors, more operators, privacy, etc.

living example

Note that y-combinator can be useful if you want to avoid having to copy yourself by reference in order to return *this to lambda, since capturing by reference implies a limited lifetime (and avoiding the use of common PTRs).

Other useful work would be to improve sub to handle-to- A links or even templates containing A as an argument. (the general sub-algorithm is not executed in C ++, since C ++ does not have the full capabilities of the meta-template, but the processing of each class of templates is currently simple in std : they are all templates of pure type or std::array ).


For completeness, you can add this to the 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 now it works recursively on many patterns, on arrays, references and pointers, and with cv-qualified types. This allows you to write something like:

 func< std::vector<recurse>() > 

which is the object of the function whose operator() returns a func< std::vector<recurse>() > .

Note that this procedure is not entirely perfect, as if some_template<recurse> not a valid instance of the template, the above will not work. A weirder version that uses potentially applicable patterns and arguments will require a replacement, and then an application.

+4
source

Source: https://habr.com/ru/post/1216632/


All Articles