gcc not_fn implementation:为什么_Not_fn接受额外的int参数?

时间:2018-05-08 19:11:46

标签: c++ gcc c++17 libstdc++

最近,我查看了 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 实现需要它?

3 个答案:

答案 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参数的引入解决了这个问题。

Live example

引入change来修复bug 70564

答案 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。