最近,我查看了 gcc 提供的implementation std::not_fn
功能模板。
此函数模板的返回类型是_Not_fn
- 一个包装类模板,它取消了一个包装的可调用对象。
事实证明,_Not_fn
constructor接受了未明确使用的其他int
参数:
template<typename _Fn2>
_Not_fn(_Fn2&& __fn, int)
: _M_fn(std::forward<_Fn2>(__fn)) { }
对构造函数的调用如下所示:
template<typename _Fn>
inline auto not_fn(_Fn&& __fn)
noexcept(std::is_nothrow_constructible<std::decay_t<_Fn>, _Fn&&>::value)
{
return _Not_fn<std::decay_t<_Fn>>{std::forward<_Fn>(__fn), 0}; // <- 0 is passed here
}
问题:
此额外int
参数的用途是什么?为什么 gcc 实现需要它?
答案 0 :(得分:8)
添加了伪参数,因为实现者并不希望完美的转发构造函数是better match而不是非const
参数的复制构造函数。
考虑这个例子
struct _Not_fn
{
template<typename _Fn2>
_Not_fn(_Fn2&&)
{ /* */ }
_Not_fn(const _Not_fn&)
{ /* */ }
};
_Not_fn f([]{});
_Not_fn f1(f); // calls perfect forwarding constructor
_Not_fn f2(const_cast<const _Not_fn&>(f)); // calls copy constructor
移动构造函数也存在同样的问题。虚拟int
参数的引入解决了这个问题。
答案 1 :(得分:1)
我可以想到两个原因。
第一个原因是,带有2个参数的构造函数不是转换构造函数。有时甚至可以通过意外调用或选择显式转换。通过添加int
,关于可兑换性的问题是明确的(事实并非如此)。
第二个原因可能是它是来自重载决策排序技巧的遗留代码。如果您创建了两个重载,一个用int
另一个...
,那么当int
都可行时,...
将被int
选中。
如果某个类型的结构更复杂,则可能会导致...
和int
超载。 const Router = require('express').Router();
const eventEmitter = require('./eventEmitter');
// sets event listener
const listener = require('./eventListener');
Router.post('/webhook', (req, res) => {
eventEmitter.emit('pubsub', req.body);
res.status(200).send('success');
});
module.exports = Router;
可能只是未清理代码的遗产。
答案 2 :(得分:0)
题外话:libstdcx ++明确定义了这些ctor:
template<typename _Fn2>
_Not_fn(_Fn2&& __fn, int)
: _M_fn(std::forward<_Fn2>(__fn)) { }
_Not_fn(const _Not_fn& __fn) = default;
_Not_fn(_Not_fn&& __fn) = default;
~_Not_fn() = default;
/*other member functions*/
template<typename _Fn>
inline auto
not_fn(_Fn&& __fn)
noexcept(std::is_nothrow_constructible<std::decay_t<_Fn>, _Fn&&>::value)
{
return _Not_fn<std::decay_t<_Fn>>{std::forward<_Fn>(__fn), 0};
}
But libcxx doesn't declare any ctor explicitly
__not_fn_imp() = delete;
__not_fn_imp
┃ ┃ (Class)
┃ ┃ operator() (Method)
┃ ┃ operator() (Method)
┃ ┃ operator() (Method)
┃ ┃ operator() (Method)
┃ ┃ __fd (Field)
所以
template <class _RawFunc>
inline _LIBCPP_INLINE_VISIBILITY __not_fn_imp<decay_t<_RawFunc> >
not_fn(_RawFunc&& __fn) {
return __not_fn_imp<decay_t<_RawFunc> >(_VSTD::forward<_RawFunc>(__fn));
}
可以找到正确的(cpoy)ctor。