deducing the argument type of overloaded function call operator

S

subramanian100in

In the following program I have used 'for_each' algorithm for learning
purpose only. (I will use ' copy' algorithm along with
ostream_iterator in real code).

Consider the program x.cpp:

#include <cstdlib>
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <fstream>

using namespace std;

class Print
{
public:
explicit Print(ostream& arg);
Print(const Print& rhs);
template <typename T> void operator()(const T& arg);

private:
ostream* os;
};

inline Print::print(ostream& arg) : os(&arg)
{
cout << "one argument ctor of Print called" << endl;
}

inline Print::print(const Print& rhs) : os(rhs.os)
{
cout << "from Print copy ctor" << endl;
}

template <typename T>
inline void Print::eek:perator()(const T& arg)
{
*os << arg << endl;
return;
}

int main()
{
cout << "Enter a set of integers" << endl;
typedef vector<int> Container;
istream_iterator<Container::value_type> isi(cin);
istream_iterator<Container::value_type> eos;
Container c(isi, eos);
ofstream ofs("output.txt");

if (!ofs)
{
cout << "Could not create output file" << endl;
return EXIT_FAILURE;
}

for_each(c.rbegin(), c.rend(), Print(ofs));

return EXIT_SUCCESS;
}

In the above program, consider the line:
for_each(c.rbegin(), c.rend(), Print(ofs));
Here I am passing a temporary function object of type 'Print' as the
third argument to the 'for_each' algorithm. The 'for_each' algorithm
will apply this function object to every iterator in the range
[c.rbegin(), c.rend()). But the overloaded function call operator will
be called with '*ri', for an iterator 'ri' in this range, only at run-
time - ie the type of the argument to the overloaded function call
operator will be known at run-time only. Am I correct ? If this is so,
I do not understand how the compiler is able to deduce at compile-time
the type 'T' of the function template namely the overloaded function
call operator given by

template <typename T> void operator()(const T& arg);

Kindly explain, if necessary with example code.

In the above program, suppose I make the class 'Print' a class
template thereby making the overloaded function call operator an
ordinary member function instead of a member function template.That is
I have:

template <typename T> class Print
{
public:
explicit Print(ostream& arg);
Print(const Print<T>& rhs);
void operator()(const T& arg);

private:
ostream* os;
};

Then the call to 'for_each' algorithm becomes:
for_each(c.rbegin(),
c.rend(),
Print<Container::value_type>(ofs));

My question: Which of the two 'for_each' algorithm calls
for_each(c.rbegin(), c.rend(), Print(ofs));
and
for_each(c.rbegin(),
c.rend(),
Print<Container::value_type>(ofs));

is efficient ? Kindly explain. Here I am just printing. In real code
the overloaded function call operator may perform some task. Given
this, which of the two approaches should be preferred ? Kindly
explain.

Thanks
V.Subramanian
 
F

Francesco S. Carta

on said:
In the following program I have used 'for_each' algorithm for learning
purpose only. (I will use ' copy' algorithm along with
ostream_iterator in real code).

Consider the program x.cpp:

In the above program, consider the line:
for_each(c.rbegin(), c.rend(), Print(ofs));
Here I am passing a temporary function object of type 'Print' as the
third argument to the 'for_each' algorithm. The 'for_each' algorithm
will apply this function object to every iterator in the range
[c.rbegin(), c.rend()). But the overloaded function call operator will
be called with '*ri', for an iterator 'ri' in this range, only at run-
time - ie the type of the argument to the overloaded function call
operator will be known at run-time only. Am I correct ?

No, everything related to templates is resolved at compile-time. In
particular, your for_each instruction is well aware that it's dealing
with a vector said:
If this is so,
I do not understand how the compiler is able to deduce at compile-time
the type 'T' of the function template namely the overloaded function
call operator given by

template<typename T> void operator()(const T& arg);

Kindly explain, if necessary with example code.

As above, all those resolutions are done at compile time. Think of
for_each as a macro that will be expanded to an appropriate, regular for
loop at compile time. There, you'll have a Print object instantiated,
and you'll have a call to its operator(), where this call will be passed
a vector said:
In the above program, suppose I make the class 'Print' a class
template thereby making the overloaded function call operator an
ordinary member function instead of a member function template.That is
I have:

template<typename T> class Print
{
public:
explicit Print(ostream& arg);
Print(const Print<T>& rhs);
void operator()(const T& arg);

private:
ostream* os;
};

Then the call to 'for_each' algorithm becomes:
for_each(c.rbegin(),
c.rend(),
Print<Container::value_type>(ofs));

My question: Which of the two 'for_each' algorithm calls
for_each(c.rbegin(), c.rend(), Print(ofs));

If Print is a templated class, you will not be able to compile the last
line above, you will need to point out the template parameter as you did
three lines above - but I'm sure you already know this.
and
for_each(c.rbegin(),
c.rend(),
Print<Container::value_type>(ofs));

is efficient ?

There is virtually no difference, because in both cases [template Print
with non-template operator()(); non-template Print with template
operator()()] the final call will be to a regular member function. In
practice, though, you'd have to profile your code in order to see if
there is any performance difference.
 
M

Michael Doubez

In the following program I have used 'for_each' algorithm for learning
purpose only. (I will use ' copy' algorithm along with
ostream_iterator in real code).

Consider the program x.cpp: [snip]

using namespace std;

class Print
{
public:
explicit Print(ostream& arg);

Using explicit here is a non-sense.
Print(const Print& rhs);
template <typename T> void operator()(const T& arg);

private:
ostream* os;

}; [snip]

template <typename T>
inline void Print::eek:perator()(const T& arg)
{
        *os << arg << endl;
        return;

}

int main()
{
        cout << "Enter a set of integers" << endl;
        typedef vector<int> Container;
        istream_iterator<Container::value_type> isi(cin);
        istream_iterator<Container::value_type> eos;
        Container c(isi, eos);
        ofstream ofs("output.txt");

        if (!ofs)
        {
                cout << "Could not create output file" << endl;
                return EXIT_FAILURE;
        }

        for_each(c.rbegin(), c.rend(), Print(ofs));

        return EXIT_SUCCESS;

}

In the above program, consider the line:
        for_each(c.rbegin(), c.rend(), Print(ofs));
Here I am passing a temporary function object of type 'Print' as the
third argument to the 'for_each' algorithm. The 'for_each' algorithm
will apply this function object to every iterator in the range
[c.rbegin(), c.rend()). But the overloaded function call operator will
be called with '*ri', for an iterator 'ri' in this range, only at run-
time - ie the type of the argument to the overloaded function call
operator will be known at run-time only. Am I correct ?

No. The type of the argument is known are compile time.
'*ri' is of type std::vector said:
If this is so,
I do not understand how the compiler is able to deduce at compile-time
the type 'T' of the function template namely the overloaded function
call operator given by

template <typename T> void operator()(const T& arg);

Kindly explain, if necessary with example  code.

The compiler will set up a list of candidate function (i.e. function
that match the name) and consider them in order (see 13.3 of the
standard).

Eventually the compiler will have a best match by instantiating a
specialisation Print::eek:perator()(const int& arg).

In the above program, suppose I make the class 'Print' a class
template thereby making the overloaded function call operator an
ordinary member function instead of a member function template.That is
I have:

template <typename T> class Print [snip]

Then the call to 'for_each' algorithm becomes:
        for_each(c.rbegin(),
                      c.rend(),
                      Print<Container::value_type>(ofs));

My question: Which of the two 'for_each' algorithm calls
        for_each(c.rbegin(), c.rend(), Print(ofs));
and
        for_each(c.rbegin(),
                      c.rend(),
                      Print<Container::value_type>(ofs));

is efficient ?

Both are equivalent.
Kindly explain.Here I am just printing. In real code
the overloaded function call operator may perform some task. Given
this, which of the two approaches should be preferred ? Kindly
explain.

This is a design issue.

There may be some advantage to using the second form because it let
you more freedom regarding partial specialisation (exemple: with the
1st form, you cannot partially specialize on template of pointer
parameters) but this comes at the cost of redefining the other member
functions of the class.
 
V

Vladimir Jovic

Michael said:
On 16 juil, 16:21, "(e-mail address removed), India"
using namespace std;

class Print
{
public:
explicit Print(ostream& arg);

Using explicit here is a non-sense.

Why?
Print(const Print& rhs);
template <typename T> void operator()(const T& arg);

private:
ostream* os;

};
[snip]
 
M

Michael Doubez


Because it doesn't add anything to the resolution rule:
1. the compiler could only instantiate an ostream if it was taking a
const reference
2. Even if changed to const reference, the only constructor of
std::eek:stream takes a pointer to a streambuf which would be the only
use for a const streambuf reference.

I know that some coders have the rule to put explicit in front of all
single argument constructors but here, it really doesn't make sense.
 
J

James Kanze

Michael said:
On 16 juil, 16:21, "(e-mail address removed), India"
[snip]
using namespace std;
class Print
{
public:
explicit Print(ostream& arg);
Using explicit here is a non-sense.
Why?
Because it doesn't add anything to the resolution rule:
1. the compiler could only instantiate an ostream if it was taking a
const reference

The explicit has nothing to do with instantiating an ostream or
not. Normally, it won't come into play unless there is already
an instantiated ostream, like std::cout.
2. Even if changed to const reference, the only constructor of
std::eek:stream takes a pointer to a streambuf which would be the only
use for a const streambuf reference.

Again, the explicit here has nothing to do with ostream. It
inhibits explicit conversion of an ostream to an Pring.
I know that some coders have the rule to put explicit in front
of all single argument constructors but here, it really
doesn't make sense.

It prevents implicit convertion, just as it always does. Given
something like:

extern void f(Print const& printer);

//
f(std::cout);

The above is illegal with the explicit, legal without it.

In general, I find it a good rule to use explicit for everything
except default and copy constructors.
 
V

Vladimir Jovic

James said:
Again, the explicit here has nothing to do with ostream. It
inhibits explicit conversion of an ostream to an Pring.


It prevents implicit convertion, just as it always does. Given
something like:

extern void f(Print const& printer);

//
f(std::cout);

The above is illegal with the explicit, legal without it.

In general, I find it a good rule to use explicit for everything
except default and copy constructors.

Have you meant here "every constructor that takes one parameter" ?
Having an explicit constructor taking 2 or more parameters makes no
sense, no?
 
Ö

Öö Tiib

Have you meant here "every constructor that takes one parameter" ?
Having an explicit constructor taking 2 or more parameters makes no
sense, no?

Yes, however whenever you say fully correct things like "use explicit
for every constructor that takes no more than one parameter without
default argument values except default constructor and copy
constructors" then (despite it is probably what James did mean) the
simpler readers do not "kindly" follow full meaning of such complex
sentences.
 
J

James Kanze

James Kanze wrote:

[...]
Have you meant here "every constructor that takes one parameter" ?
Having an explicit constructor taking 2 or more parameters makes no
sense, no?

Until someone adds a default argument for the last variables.
Adding explicit when there is more than one parameter doesn't
have any real effect, as far as the compiler is concerned. But
it's easier to just do it, systematically, and if you do so,
there won't be problems later.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top