_Not_fn 函数调用运算符的 noexcept 说明符
noexcept specifier for _Not_fn function call operator
在这个问题中,我考虑了 _Not_fn
调用包装器的 libstdc++ implementation。
定义了四种函数调用运算符的重载如下:
#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 规范背后的逻辑,我得出结论:
- 函数调用运算符在概念上与
_S_not<__inv_res_t<_Fn _QUALS, _Args...>>
. 具有相同的 noexcept 规范
_S_not<__inv_res_t<_Fn _QUALS, _Args...>>
被标记为 noexcept 取决于应用于 std::__invoke(...)
结果的否定是否为 noexcept。
从我的角度来看,这个 noexcept 规范没有涵盖以下情况:包装在 not_fn
中的可调用对象在使用一组特定的参数调用时可能会或可能不会抛出自身not_fn
函数调用运算符。换句话说,不会检查函数调用运算符中的 std::__invoke(...)
本身是否可能抛出 。
我是否遗漏了此实现中的某些内容?
来自 cppreference.com has a bit simpler noexcept specification. However, this implementation doesn't work with the latest g++ due to a known issue 的实现。
实际上没有要求 not_fn
传播 noexcept
。它在 [func.not_fn] 中指定,四个调用运算符中的每一个都类似于:
template<class... Args>
auto operator()(Args&&...) const&
-> decltype(!declval<invoke_result_t<const FD&, Args...>>());
没有noexcept
。也就是说,P0356 proposes to add it and the current noexcept
specifier makes no sense and could cause harm by being wrong, so filed 87538。
更新:此问题已在 7.4、8.3 和 9.1 中修复。
在这个问题中,我考虑了 _Not_fn
调用包装器的 libstdc++ implementation。
定义了四种函数调用运算符的重载如下:
#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 规范背后的逻辑,我得出结论:
- 函数调用运算符在概念上与
_S_not<__inv_res_t<_Fn _QUALS, _Args...>>
. 具有相同的 noexcept 规范
_S_not<__inv_res_t<_Fn _QUALS, _Args...>>
被标记为 noexcept 取决于应用于std::__invoke(...)
结果的否定是否为 noexcept。
从我的角度来看,这个 noexcept 规范没有涵盖以下情况:包装在 not_fn
中的可调用对象在使用一组特定的参数调用时可能会或可能不会抛出自身not_fn
函数调用运算符。换句话说,不会检查函数调用运算符中的 std::__invoke(...)
本身是否可能抛出 。
我是否遗漏了此实现中的某些内容?
来自 cppreference.com has a bit simpler noexcept specification. However, this implementation doesn't work with the latest g++ due to a known issue 的实现。
实际上没有要求 not_fn
传播 noexcept
。它在 [func.not_fn] 中指定,四个调用运算符中的每一个都类似于:
template<class... Args> auto operator()(Args&&...) const& -> decltype(!declval<invoke_result_t<const FD&, Args...>>());
没有noexcept
。也就是说,P0356 proposes to add it and the current noexcept
specifier makes no sense and could cause harm by being wrong, so filed 87538。
更新:此问题已在 7.4、8.3 和 9.1 中修复。