【问题标题】:why are there std::not1() and std::not2() rather than a single overloaded std::not_()?为什么有 std::not1() 和 std::not2() 而不是单个重载的 std::not_()?
【发布时间】:2025-11-21 11:00:02
【问题描述】:

C++ std 命名空间包含辅助函数 std::not1std::not2。它们都分别采用一元或二元谓词函子,并分别返回 std::unary_negatestd::binary_negate 谓词。

我想知道是否应该使用一些模板魔法来拥有

template<typename Predicate> inline
enable_if_t<is_unary_predicate<Predicate>::value, unary_negate<Predicate> >
not_(Predicate const&pred)
{ return unary_negate<Predicate>{pred}; }

template<typename Predicate> inline
enable_if_t<is_binary_predicate<Predicate>::value, binary_negate<Predicate> >
not_(Predicate const&pred)
{ return binary_negate<Predicate>{pred}; }

它区分参数pred 传递以返回适当的谓词。当然,在某些奇怪的情况下,传递的对象 pred 具有两种类型的运算符(一元和二元),此时这不起作用,但可以在不使用此辅助函数的情况下处理这些情况。

【问题讨论】:

  • not 是关键字,因此无法使用
  • @DieterLücking 好吧,那就叫它not_()吧。
  • @RahulTripathi 好地方。我引用的 cppreference 实际上声明这些函数在 C++14 之前是标准的一部分,因此在此之后不推荐使用。所以,我认为,这回答了它。不幸的是,cppreference 和您引用的来源都没有提供替代方案。
  • @Walter 替代方案是 lambdas。
  • @Walter:- 下一页说:Being able to use lambda is really an improvement here

标签: c++ template-meta-programming sfinae


【解决方案1】:

在没有 C++11 功能的情况下计算出正确的重载并非易事。在设计 STL 并提出这些函数对象时,甚至没有编译器能够编译其中的一些函数。结果,一些功能比原本更难使用。例如,创建一个std::not_() 函数是完全可行的(std::not() 是不可能的,因为not 恰好是一个替代标记,因此不是一个可行的函数名称)。也就是说,答案是:这多半是历史上的意外。

很有可能std::not1std::not2 是在函数重载的部分排序规则还很混乱的时候提出的。 STL 的主要提案是在 1994 年或 1995 年完成的(我无法在 mailing archive 中快速找到它)。如果根据 STL 提案实际更改了重载规则,我不会感到惊讶。

也就是说,其他人花了几年时间才跟上步伐并开发出这些界面的改进版本。 Boost 引领了这些发展。

关于实现魔法,创建一个使用各种类型的 not_ 函数实际上可能非常简单:

template <typename Pred>
class not_fn_t {
    std::decay_t<Pred> pred;
public:
    explicit not_fn_t(Pred p): pred(p) {}
    template <typename... A>
    bool operator()(A&&... a) const {
        return !this->pred(std::forward<A>(a)...);
    }
};
template <typename Pred>
not_fn_t<Pred> not_fn(Pred&& pred) {
    return not_fn_t<Pred>(std::forward<Pred>(pred));
}

实际上,这几乎就是在上次会议上以std::not_fn() 投票进入 C++ 工作论文的内容。这是一个 C++11 公式,但道德上的等价物可以用早期版本的 C++ 完成,只需为每个支持的参数扩展函数调用运算符(显然,没有完美的转发)。

【讨论】:

  • not 不是有向图,它是"Alternative token"
  • "不是词法关键字" - 'not' 是词法关键字,所以不是二合字母。
  • 不应该是return ! this-&gt;pred(std::forward&lt;A&gt;(a)...);这样的东西吗?您不会在任何地方反转结果。
  • @anderas:哦,是的 - 我专注于让基础设施正确,但没有过多关注实际逻辑(已修复)
  • std::unary_negate 有一个 explicit 构造函数,而不是你的 not_fn_t - 这种差异之间的基本原理是什么?如果没有explicit,您可以只在not_fn() 中使用return {std::forward&lt;Pred&gt;(pred)};。顺便说一句,您在 return 语句中返回的 not_fn_t 类型与函数返回类型中承诺的不同...
【解决方案2】:

2013 年有一个类似的提案:N3699 A proposal to add a generalized callable negator。这已经有一段时间了(最新版本是 N4022),看起来像 should make it into the second Library Fundamentals TS;它出现在 Library Fundamentals TS 2 draft n4564func.not_fn 部分中。

not1not2 存在于标准中的原因是它们已经存在了很长一段时间,因为在元编程技术存在之前,支持单个否定者是必需的。

【讨论】:

    最近更新 更多