2

假设我想创建一个作用于某种通用类型的函子。例如

template<typename Ape>
class functor1
{
   void operator()(Ape& m)
   {
      // Do something to m
   }
};

这一直是我做事的标准方式。不过,我还有另一种方法:

class functor2
{
   template<typename Ape>
   void operator()(Ape& m)
   {
      // Do something to m
   }
};

第二种方法的优点是我不必明确说明模板的类型。

int main()
{
   std::vector<chimpanzee> chimps(100);
   for_each(chimps.begin(), chimps.end(), functor1<chimpanzee>()); // Explicity state the type
   for_each(chimps.begin(), chimps.end(), functor2()); // Less typing. Will it work?
}

第二个版本能用吗?还是我错过了什么?如果可行,第一种方法有什么好处吗?

4

3 回答 3

3

明显的区别是,在第一种情况下,您明确指定类型,而在第二种情况下,编译器将在实际调用的上下文中为您推断类型。但是,在您的具体示例中,它可能根本没有真正的区别。

  1. 如果您的类中有多个成员函数,则第一个变体将为所有成员“修复”相同的模板参数,而在第二个变体中,将为每个成员函数独立推导出参数。

    当从多个上下文调用单个成员函数时也是如此:每个上下文将在第二个变体中执行其自己的模板参数推导。

    它可能好也可能不太好,这取决于你的意图。

  2. 如果您的函数通过值(或通过const引用)接受其参数,则在第一个变体中,您可以为参数指定与存储在容器中的类型不同的类型。例如,您可以为 s 创建一个仿函数long并将其应用于ints 的容器。这在第二个变体中是不可能的。

    例如,如果您的chimpanzee类是多态的,派生自animal,您可以使用 afunctor1<animal>来迭代此类容器。在第二个变体中,模板参数将为您推断为chimpanzee,而不是animal

  3. 如果你的类有数据成员,第二个变体将确保成员函数的所有特化共享相同的数据,如果使用相同的仿函数对象。在第一个变体中,每个专业化都是一个不同的类,它有自己的数据。

于 2012-07-11T14:25:17.437 回答
1

对于没有状态的函子,这应该是相同的。经常(比较)您需要在仿函数中存储另一个相同类型的对象/引用/指针,而您的第二个选项在这种情况下不起作用。请注意,如果您的仿函数确实需要构造函数参数,您可以创建一个免费函数,make_<foo>例如make_pair为您推断类型并再次减少输入。

于 2012-07-11T14:22:06.927 回答
1

就像作用域一样: in functor1,类中的任何东西都可以使用类型Ape(对于成员声明、参数和返回类型、特征或其他类型),而 infunctor2Ape表示operator(). 简而言之:

  • 定义时间:
    • functor1需要知道Ape它是什么时候创建的。
    • functor2Ape在它被调用之前不需要知道。
  • 类型范围:
    • 里面的一切都functor1知道Ape
    • 只有operator()functor2知道Ape
  • 实例的多功能性:
    • functor1实例仅适用于单一类型的Ape.
    • functor2实例适用于任何类型的Ape.
于 2012-07-11T14:34:43.043 回答