为什么有 std::not1() 和 std::not2() 而不是一个重载的 std::not_()?
why are there std::not1() and std::not2() rather than a single overloaded std::not_()?
C++ std
命名空间分别包含辅助函数 std::not1
and std::not2
. They both take a unary or binary predicate functor, respectively, and return a std::unary_negate
or std::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
传递给 return 适当的谓词。当然,也有一些奇怪的情况,即传递的对象 pred
具有两种类型的运算符(一元和二元),这将不起作用,但可以在不使用此辅助函数的情况下处理这些情况。
在没有 C++11 功能的情况下计算出正确的重载并非易事。在设计STL和提出这些函数objects的时候,甚至没有一个编译器能够编译其中的一些函数。结果,一些功能比原本更难使用。例如,创建一个 std::not_()
函数是完全可行的(std::not()
是不可能的,因为 not
恰好是一个替代标记,因此不是一个可行的函数名称).即答案是:多为历史偶然
很可能 std::not1
和 std::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++ 完成,只需为每个支持的元数扩展函数调用运算符(显然,没有完美转发)。
2013 年有一个类似的提议:N3699 A proposal to add a generalized callable negator. This has bumped along for some time (most recent version is N4022) and looks like it should make it into the second Library Fundamentals TS; it's present in section func.not_fn in Library Fundamentals TS 2 draft n4564。
标准中存在 not1
和 not2
的原因是它们已经存在了很长一段时间,因为在元编程技术存在之前,支持单个否定器是必需的。
C++ std
命名空间分别包含辅助函数 std::not1
and std::not2
. They both take a unary or binary predicate functor, respectively, and return a std::unary_negate
or std::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
传递给 return 适当的谓词。当然,也有一些奇怪的情况,即传递的对象 pred
具有两种类型的运算符(一元和二元),这将不起作用,但可以在不使用此辅助函数的情况下处理这些情况。
在没有 C++11 功能的情况下计算出正确的重载并非易事。在设计STL和提出这些函数objects的时候,甚至没有一个编译器能够编译其中的一些函数。结果,一些功能比原本更难使用。例如,创建一个 std::not_()
函数是完全可行的(std::not()
是不可能的,因为 not
恰好是一个替代标记,因此不是一个可行的函数名称).即答案是:多为历史偶然
很可能 std::not1
和 std::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++ 完成,只需为每个支持的元数扩展函数调用运算符(显然,没有完美转发)。
2013 年有一个类似的提议:N3699 A proposal to add a generalized callable negator. This has bumped along for some time (most recent version is N4022) and looks like it should make it into the second Library Fundamentals TS; it's present in section func.not_fn in Library Fundamentals TS 2 draft n4564。
标准中存在 not1
和 not2
的原因是它们已经存在了很长一段时间,因为在元编程技术存在之前,支持单个否定器是必需的。