2013-08-09 2 views
4

Я реализовал смарт-указатель, который хранит объект типа T с функцией прокси, который вызывает методы внутреннего объекта в:Как использовать noexcept оператор правильно

template <class Function, class ...Args, class ...Params> 
inline bool call(Function (T::*function)(Args...) const, Params&& ...args) const noexcept(noexcept(function)); 

Но я нашел странную проблему - когда std :: exception генерируется в функции-члене, программа завершается, даже если функция прокси вызывается внутри блока try. Поэтому мой вопрос: правильно ли использовать оператор noexcept, а если нет, как его использовать в этом случае?

+0

Что не так с умными указателями уже в C++ 11 и/или 'std :: function'? –

+0

Он использует копию для записи в некоторых особых случаях. И он делает все обращения к сохраненному объекту потоком безопасным. –

+0

См. [Здесь] (http://en.cppreference.com/w/cpp/language/noexcept_spec), в частности «Если функция, помеченная' noexcept', позволяет избежать неперехваченного исключения во время выполнения, 'std :: terminate' является вызванный немедленно ». – juanchopanza

ответ

4

Перли C++ 11 §5.3.7/1:

noexcept оператор определяет, является ли оценка ее операнда, который является невычисленным операндом (раздел 5), может вызывать исключение (15.1) ,

Вычисление выражения (function) не может бросить исключение, поэтому noexcept(function) вычисляется в true. Обратите внимание, что это не то же самое, что и выражение (*function)(std::forward<Params>(args)...), noexcept((*function)(std::forward<Params>(args)...)), безусловно, оценивается до false, так как указатель функции-члена не квалифицирован noexcept.

noexcept является квалификацией по типам указателей функций, таких как const. Так как указатель функции call принимает NOT noexcept -qualified, этот сложный noexcept(noexcept(...)) всегда будет оценивать как noexcept(false).

EDIT: ниже неправильно, это не возможно перегружать исключительно на основе noexcept квалификации указателя функции, так как «исключение-спецификация не считается частью типа А функции.» (§15.4/13)

Если вы хотите call быть noexcept когда дано noexcept -qualified указатель на функцию-член, необходимо обеспечить перегрузку call(R (T::*)() const noexcept, ...).

+0

Спасибо вам за ответ! Так что я должен использовать его вот так: noexcept (noexcept (* function (std: forward (args) ...)) ? –

+1

@PavelDavydov Да, это правильно. Это действительно забавно, когда у вас есть то же самое выражение в выражении 'noexcept', в концевом типе возвращаемого значения и в теле функции;)' auto foo (...) -> decltype (expr) noexcept (noexcept (expr)) {return expr; } ' – Casey

+0

Выглядит круто =). Я некоторое время думал о том, как заставить его работать с функциями, которые имеют тип возврата, отличный от bool, теперь я это знаю, спасибо! –