【问题标题】:Why are the STL functors themselves templated and not their function call operator?为什么 STL 仿函数本身是模板化的,而不是它们的函数调用运算符?
【发布时间】:2011-09-28 09:23:54
【问题描述】:

STL 函子是这样实现的:

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

这让我们每次创建这样的仿函数时都会提到(可能是长的)类型。为什么它们没有像下面显示的那样实现?有什么原因吗?

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

这将使它们无需提及(可能很长)类型即可使用。

【问题讨论】:

  • 从 C++14 开始,您可以使用提供 template&lt;class T&gt; std::less&lt;T=void&gt;transparant comparators 和包含模板化 operator&lt;std::less&lt;void&gt;(对于其他仿函数也类似)。

标签: c++ templates stl functor


【解决方案1】:

这也使得将它们专门用于用户定义的类型是不可能的。

它们应该是一个自定义点。


总结一下cmets中的讨论:

尽管按照 Xeo 的建议在技术上是可行的,但语言标准不允许这样做。

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

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

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

由于没有“另外指定” Xeo 的代码是允许的,我们理解它是不允许的。也许并不完全明显!或者说“模板特化”只适用于类。

新的 C++11 标准对这部分进行了扩展,并对其进行了更详细的说明(17.6.4.2):

除非另有说明,否则如果 C++ 程序将声明或定义添加到命名空间 std 或命名空间 std 内的命名空间,则其行为未定义。仅当声明依赖于用户定义的类型并且特化满足原始模板的标准库要求且未明确表示时,程序才可以将任何标准库模板的模板特化添加到命名空间 std 禁止。

如果 C++ 程序声明了,则其行为是未定义的

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

只有当声明依赖于用户定义类型的名称并且实例化符合标准库对原始模板的要求时,程序才能显式实例化标准库中定义的模板。

【讨论】:

  • 嗯.. 自己制作怎么样?无论如何,您都需要创建一个“新”结构。
  • 万一Bo说的很难理解,你可能要定义模板 bool less<:string>::operator()(...) {... }
  • @poule: template&lt;&gt; bool std::less::operator()&lt;std::string&gt; ?还是我错过了什么?
  • @Xeo 那么你总是需要指定你的自定义函子,而 less&lt;your_type&gt; 在大多数地方都可以推断出来。
  • @Xeo - 请!不能,如不允许。你被允许从命名空间std中专门化types
【解决方案2】:

也许:

std::multiset<long, std::less<int> > moduloset;

奇怪的事情,但重点是std::less&lt;int&gt;std::less&lt;long&gt;std::less&lt;unsigned int&gt; 实现了不同的数学函数,当传递(转换的结果)某些参数表达式时会产生不同的结果。各种算法和其他标准库组件通过指定一个仿函数来工作,因此对我来说,有不同的仿函数来表示这些不同的数学函数是有意义的,而不仅仅是一个仿函数上的 operator() 的不同重载。

此外,带有模板operator() 的函子不能是自适应二元谓词,因为它没有参数类型(参数可以有任何类型)。所以如果std::less 是按照你的建议定义的,那么它就不能参与&lt;functional&gt; 中的内容。

还有一个高度推测性的注释——std::less 可能是在对模板成员函数的支持完全普及之前设计的,因为 SGI STL 文档中有各种注释说,“如果你的实现不支持成员模板那么这不可用”。对于这样一个简单的组件,我想,会是一种激励去做今天有效的事情。一旦存在,标准化可以将其删除以支持其他内容,但是否值得破坏现有代码?如果有那么大的问题,那么您或标准都可以按照您的描述引入 flexible_less 函子。

最后,为什么

template<class T>
bool operator()(T const& lhs, T const& rhs){
  return lhs < rhs;
}

而不是

template<class T, class U>
bool operator()(T const& lhs, U const& rhs){
  return lhs < rhs;
}

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

【讨论】:

  • “因为我不知道为什么没有 std::less 的两个模板参数版本” - 提出一个新问题! :P
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多