Iam
Iam

Reputation: 401

Templated functor in C . Class template vs Function template

Suppose I want to create a functor that acts upon some general type. For example

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

This has been the standard way of doing things for me. However, I also have another way:

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

The advantage of the second approach is that I don't have to explicitly state the type of the template.

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?
}

Will the second version work? Or am I missing something? If it works are there any advantages to the first approach?

Upvotes: 2

Views: 268

Answers (3)

Mike DeSimone
Mike DeSimone

Reputation: 42805

It's like scoping: in functor1, anything in the class can use the type Ape (for member declarations, parameter and return types types, traits, or whatever), while in functor2, Ape only means something within the scope of operator(). In short:

  • Time of definition:
    • functor1 needs to know about Ape when it is created.
    • functor2 doesn't need to know about Ape until it is called.
  • Scope of type:
    • Everything in functor1 knows about Ape.
    • Only operator() in functor2 knows about Ape.
  • Versatility of an instance:
    • A functor1 instance only works with a single type of Ape.
    • A functor2 instance works with any type of Ape.

Upvotes: 1

AnT stands with Russia
AnT stands with Russia

Reputation: 320531

The obvious difference is that in the first case you specify the type explicitly, and in the second case it is the compiler that will deduce the type for you in the context of the actual call. However, in you specific example it might make no real difference at all.

  1. If your class had multiple member functions in it, the first variant would "fix" the same template parameter for all of them, while in the second variant the parameter would be deduced for each member function independently.

    The same is true when a single member function is called from multiple contexts: each context will perform its own template argument deduction in the second variant.

    It could be good or not so good, depending on your intent.

  2. If your function accepted its argument by value (or by const reference), in the first variant you could specify a different type for the argument than the one stored in the container. For example, you could have created a functor for long and applied it to the container of ints. This is not possible in the second variant.

    For example, if your chimpanzee class was polymorphic, derived from animal, you could have used a functor1<animal> to iterate over such container. In the second variant the template parameter will be deduced for you as chimpanzee, not as animal.

  3. If your class had data members, the second variant would make sure that all specializations of member function(s) share the same data, if the same functor object is used. In the first variant each specialization is a different class, it gets its own data.

Upvotes: 3

Mark B
Mark B

Reputation: 96251

For functors with no state this should be the same. Frequently (compares) you need to store another object/ref/pointer of the same type in the functor and your second option wouldn't work in that case. Note that if your functor does need constructor parameters you can make a free function make_<foo> like make_pair to deduce the type for you and again reduce typing.

Upvotes: 1

Related Questions