2013-09-16 2 views
4

Рассмотрим функцию, которая обертывает какую-то другую функцию, но делает что-то после завернутого вызова.Как сохранить статически необязательное значение

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

Как расширить это на функции обертывания, которые возвращают void? Легко добавить еще одну специализацию, но я ищу другой способ, который может быть идиоматичным.

Общая идея заключается в том, что может быть или не быть значение. Это похоже на время компиляции optional.

+0

@Nawaz: Да, неважно: -S –

ответ

4

Это законно, чтобы вернуться к исполнению вашей функции:

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

Теперь, чтобы сделать что-то после вашего звонка, вы можете сделать это в деструкторе объекта:

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)...); 
} 
+0

Я думал то же самое. Это может быть лучше? Скажите, хочу ли я напечатать некоторые параметры? то мы должны передать их конструктору, что делает его менее интересным. – Nawaz

+1

Ну, это что-то. На самом деле, я специально не хочу, чтобы он выполнялся, если было исключение. Существует 'std :: uncaught_exception', который приходит oh так близко к тому, что это работает ... – Potatoswatter

+0

@Potatoswatter Я играю вокруг некоторых, но я все же думаю, что' enable_if' может быть более уместным в этом случае - я не вижу легкого способ имитировать такое же поведение в случае исключений. Но, возможно, у кого-то еще больше успеха. – nijansen

1

Самый простой способ - выполнить дополнительный код в деструкторе локального объекта. Это позволяет непосредственно передать результат через тоже, что может игнорировать копирования/перемещения в противном случае необходимых пихты без Lvalue возвращается:

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)...); 
} 
+0

Это то же самое, что и другой ответ. Я считаю, что это невозможно сделать так, как это происходит с оригиналом при выходе из-за исключения, в случае, если он выполняется из стека. – Potatoswatter

0

Вот попытка переместить проблему на выделенную обертку в такой форме, его можно хотя бы повторно использовать.

Не уверенный в правильности, даже не попытался скомпилировать его один раз. По крайней мере, static_cast делает ненужную копию при возврате по значению.

Я просто делаю это из любопытства, на самом деле не нуждаюсь в решении этой проблемы, но это выглядит довольно обременительно.

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)); 
} 
Смежные вопросы