Reputation: 401
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
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:
functor1
needs to know about Ape
when it is created.functor2
doesn't need to know about Ape
until it is called.functor1
knows about Ape
.operator()
in functor2
knows about Ape
.functor1
instance only works with a single type of Ape
.functor2
instance works with any type of Ape
.Upvotes: 1
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.
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.
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 int
s. 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
.
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
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