为什么STL仿函数本身是模板化的,而不是它们的函数调用运算符?

Xeo*_*Xeo 22 c++ templates stl functor

STL仿函数的实现方式如下:

template<class T>
struct less{
  bool operator()(T const& lhs, T const& rhs){
    return lhs < rhs;
  }
};
Run Code Online (Sandbox Code Playgroud)

这使我们每次创建这样的仿函数时都会提到(可能很长)类型.为什么它们没有如下所示实现?有什么原因?

struct less{
  template<class T>
  bool operator()(T const& lhs, T const& rhs){
    return lhs < rhs;
  }
};
Run Code Online (Sandbox Code Playgroud)

这将使它们可用而不提及(可能很长)类型.

Bo *_*son 23

它也使得无法将它们专门用于用户定义的类型.

它们应该是一个定制点.


总结评论中的讨论:

虽然技术上可以像Xeo建议的那样做,但语言标准不允许这样做.

如果允许用户专门化模板的各个功能,则很难编写工作类模板.在某些情况下,将整个类专门化为用户定义的类型可能是个好主意.

因此C++ 98标准写道(17.4.3.1):

除非另有说明,否则C++程序未定义向命名空间std中的命名空间std或命名空间添加声明或定义.程序可以将任何标准库模板的模板特化添加到命名空间std.

因为没有"另外指定"允许Xeo的代码,我们应该理解它不是.也许并不完全明显!或者"模板特化"仅适用于类.

新的C++ 11标准已经扩展了这一部分,并详细说明了它(17.6.4.2):

如果C++程序向命名空间std或命名空间std中的命名空间添加声明或定义,则它是未定义的,除非另有说明.只有当声明取决于用户定义的类型并且特化符合原始模板的标准库要求且未明确禁止时,程序才可以将任何标准库模板的模板特化添加到命名空间std.

如果声明,C++程序的行为是不确定的

- 标准库类模板
的任何成员函数的显式特化,或- 标准库类或类模板的任何成员函数模板的显式特化,或- 标准库
的任何成员类模板的显式或部分特化类或类模板.

仅当声明取决于用户定义类型的名称并且实例化符合原始模板的标准库要求时,程序才可以显式实例化标准库中定义的模板.

  • @Xeo然后你总是需要指定你的自定义函子,而在大多数地方都可以推断出`less <your_type>`. (2认同)
  • @Xeo - 拜托!不能,因为**不允许**.****允许**从命名空间std专门化**类型**. (2认同)

Ste*_*sop 5

也许:

std::multiset<long, std::less<int> > moduloset;
Run Code Online (Sandbox Code Playgroud)

奇怪的事情,但问题是std::less<int>,std::less<long>,std::less<unsigned int>实现通过当某些参数表达式(转换的结果)产生不同的结果,不同的数学函数.各种算法和其他标准库组件通过指定仿函数来工作,因此有意义的是,有不同的仿函数来表示这些不同的数学函数,而不仅仅是operator()一个仿函数的不同重载.

此外,带有模板的仿函数operator()不能是Adaptable Binary Predicate,因为它没有参数类型(参数可以包含任何类型).因此,如果std::less按照您的建议进行定义,则无法参与其中<functional>.

另外,在一个高度推测的说明中 - std::less可能是在对模板成员函数的支持普遍存在之前设计的,因为SGI STL文档中有各种说明,"如果您的实现不支持成员模板,那么这不是可用".对于这样一个简单的组件,我想,这是一种激励去做今天有用的事情.一旦它存在,标准化可以删除它而不是其他东西,但它是否值得破坏现有代码?如果这是一笔大交易,那么你或者标准可以flexible_less像你描述的那样引入一个仿函数.

最后,为什么

template<class T>
bool operator()(T const& lhs, T const& rhs){
  return lhs < rhs;
}
Run Code Online (Sandbox Code Playgroud)

而不是

template<class T, class U>
bool operator()(T const& lhs, U const& rhs){
  return lhs < rhs;
}
Run Code Online (Sandbox Code Playgroud)

对于用户定义的类型,两者可能不同.是的,这是一个不公平的问题,因为我不知道为什么没有双模板参数版本std::less;-)