How to store a statically optional value

Consider a function that wraps some other function, but does something after a wrapped call.

template< typename ftor, typename ... args > typename std::result_of< ftor( args ... ) >::type call_and_report( ftor && f, args && ... a ) { auto && ret{ f( std::forward< args >( a ) ... ) }; std::cout << "Done!\n"; return std::forward< typename std::result_of< ftor( args ... ) >::type > ( ret ); } 

How to extend this to carry functions returning void ? It's easy to add another specialization, but I'm looking for another way that could be idiomatic.

The general idea is that there may or may not be meaning. This is similar to compilation time optional .

+4
source share
3 answers

It is legal to return with the performance of your function:

 template <typename F, typename ... Args> auto call_and_report(F && f, Args && ... a) -> decltype(f(std::forward<Args>(a)...)) { return f(std::forward<Args>(a)...); } 

Now, to do something after your call, you can do it in the object's destructor:

 template <typename F, typename ... Args> auto call_and_report(F && f, Args && ... a) -> decltype(f(std::forward<Args>(a)...)) { struct execute { ~execute() { std::cout << "Done!" << '\n'; } } execute; return f(std::forward<Args>(a)...); } 
+4
source

The easiest way is to execute additional code in the destructor of the local object. This allows you to directly pass the result through, too, which can speed up copying / moving, otherwise returning fir non-lvalue is required:

 template <typename F, typename... Args> ... call_and_forward(F&& f, Args&&... args) { struct report { ~report() { std::cout << "done\n"; } } reporter; return f(std::forward<Args>(args)...); } 
+1
source

Here is an attempt to move the task to the selected shell in such a way that it can at least be reused.

Not sure of the correctness, did not even try to compile it once. At the very least, static_cast makes an unnecessary copy when returning by value.

I just do it out of curiosity, I really do not need to solve this problem, but it looks quite burdensome.

 template< typename ftor, typename ... args > typename std::enable_if< ! std::is_void< typename std::result_of< ftor( args ... ) >::type >::value, typename std::result_of< ftor( args ... ) >::type >::type call_or_wrap_void( ftor && f, args && ... a ) { return std::forward< ftor >( f ) ( std::forward< args >( a ) ... ); } struct void_wrapper {}; template< typename ftor, typename ... args > typename std::enable_if< std::is_void< typename std::result_of< ftor( args ... ) >::type >::value, void_wrapper >::type call_or_wrap_void( ftor && f, args && ... a ) { std::forward< ftor >( f ) ( std::forward< args >( a ) ... ); return {}; } template< typename ftor, typename ... args > typename std::result_of< ftor( args ... ) >::type call_and_report( ftor && f, args && ... a ) { auto && ret{ call_or_wrap_void( std::forward< ftor >( f ), std::forward< args >( a ) ... ) }; std::cout << "Done!\n"; return static_cast< typename std::result_of< ftor( args ... ) >::type > ( std::move( ret ) ); } 
0
source

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


All Articles