noexcept спецификатор для оператора вызова функции _Not_fn - PullRequest
0 голосов
/ 06 октября 2018

В этом вопросе я рассматриваю реализацию libstdc ++ оболочки вызовов _Not_fn.

Она определяет четыре перегрузки оператора вызова функции следующим образом:

 #define _GLIBCXX_NOT_FN_CALL_OP( _QUALS )                          \
       template<typename... _Args>                                  \
    decltype(_S_not<__inv_res_t<_Fn _QUALS, _Args...>>())           \
    operator()(_Args&&... __args) _QUALS                            \
    noexcept(noexcept(_S_not<__inv_res_t<_Fn _QUALS, _Args...>>())) \
    {                                                               \
      return !std::__invoke(std::forward< _Fn _QUALS >(_M_fn),      \
                            std::forward<_Args>(__args)...);        \
    }
       _GLIBCXX_NOT_FN_CALL_OP( & )
       _GLIBCXX_NOT_FN_CALL_OP( const & )
       _GLIBCXX_NOT_FN_CALL_OP( && )
       _GLIBCXX_NOT_FN_CALL_OP( const && )
 #undef _GLIBCXX_NOT_FN_CALL

Легко видеть, что спецификация noexcept установлена ​​как:

noexcept(noexcept(_S_not<__inv_res_t<_Fn _QUALS, _Args...>>()))

, где __inv_res_t - шаблон псевдонима:

template<typename _Fn2, typename... _Args>
using __inv_res_t = typename __invoke_result<_Fn2, _Args...>::type;

и _S_not является шаблоном статической функции-члена:

template<typename _Tp>
static decltype(!std::declval<_Tp>())
_S_not() noexcept(noexcept(!std::declval<_Tp>()));

Теперь, следуя логике, лежащей в основе спецификации noexcept, я заключаю, что:

  1. Оператор вызова функции концептуально имеет ту же спецификацию noexcept, что и _S_not<__inv_res_t<_Fn _QUALS, _Args...>>.
  2. _S_not<__inv_res_t<_Fn _QUALS, _Args...>> помечается как noexcept, в зависимости от того, является ли отрицание, примененное к результату std::__invoke(...), исключением.

С моей точки зрения, эта спецификация noexcept не распространяется на случай, когда вызываемый объект, заключенный в not_fn, может или не может сам броситься, будучи вызванным с определенным набором аргументов.передан в not_fn вызов функцииоператор.Другими словами, не проверяется, может ли само std::__invoke(...) внутри оператора вызова функции выдавать или нет .

Я что-то упускаю в этой реализации?

реализация от cppreference.com имеет немного более простую, кроме спецификации.Однако эта реализация не работает с последней версией g ++ из-за известной проблемы .

1 Ответ

0 голосов
/ 06 октября 2018

На самом деле нет требования, чтобы not_fn распространялось noexcept.Он указан в [func.not_fn] , каждый из четырех операторов вызова выглядит примерно так:

template<class... Args>
  auto operator()(Args&&...) const&
    -> decltype(!declval<invoke_result_t<const FD&, Args...>>());

Нет noexcept.Тем не менее, P0356 предлагает добавить его, и текущий спецификатор noexcept не имеет смысла и может причинить вред, будучи ошибочным, поэтому подал 87538 .

Обновление: это было исправлено для 7.4, 8.3 и 9.1.

...