deducing the argument type of overloaded function call operator

Discussion in 'C++' started by subramanian100in@yahoo.com, India, Jul 16, 2010.

  1. , India

    , India Guest

    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
    , India, Jul 16, 2010
    #1
    1. Advertising

  2. , India <>, on
    16/07/2010 07:21:55, wrote:

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

    > 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<int>

    > 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<int>::reverse_iterator parameter.

    >
    > 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.

    --
    FSC - http://userscripts.org/scripts/show/59948
    http://fscode.altervista.org - http://sardinias.com
    Francesco S. Carta, Jul 16, 2010
    #2
    1. Advertising

  3. On 16 juil, 16:21, ", India"
    <> wrote:
    > 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<int>::iterator::reference.

    > 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.

    --
    Michael
    Michael Doubez, Jul 16, 2010
    #3
  4. Michael Doubez wrote:
    > On 16 juil, 16:21, ", India"
    > <> wrote:
    > [snip]
    >> 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]
    Vladimir Jovic, Jul 16, 2010
    #4
  5. On 16 juil, 17:36, Vladimir Jovic <> wrote:
    > Michael Doubez wrote:
    > > On 16 juil, 16:21, ", India"
    > > <> wrote:
    > > [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
    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.

    --
    Michael
    Michael Doubez, Jul 18, 2010
    #5
  6. , India

    James Kanze Guest

    On Jul 18, 2:31 pm, Michael Doubez <> wrote:
    > On 16 juil, 17:36, Vladimir Jovic <> wrote:
    >
    > > Michael Doubez wrote:
    > > > On 16 juil, 16:21, ", India"
    > > > <> wrote:
    > > > [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.

    --
    James Kanze
    James Kanze, Jul 18, 2010
    #6
  7. James Kanze wrote:
    >> 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.


    Have you meant here "every constructor that takes one parameter" ?
    Having an explicit constructor taking 2 or more parameters makes no
    sense, no?
    Vladimir Jovic, Jul 19, 2010
    #7
  8. , India

    Öö Tiib Guest

    On 19 juuli, 09:09, Vladimir Jovic <> wrote:
    > James Kanze wrote:
    > >>   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.

    >
    > 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.
    Öö Tiib, Jul 19, 2010
    #8
  9. , India

    James Kanze Guest

    On Jul 19, 7:09 am, Vladimir Jovic <> wrote:
    > James Kanze wrote:


    [...]
    > > 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?


    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.

    --
    James Kanze
    James Kanze, Jul 19, 2010
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. glen stark
    Replies:
    3
    Views:
    532
    glen stark
    Sep 30, 2003
  2. mathieu
    Replies:
    1
    Views:
    280
    Victor Bazarov
    Dec 12, 2006
  3. George2

    Deducing Function Template Arguments

    George2, Mar 12, 2008, in forum: C Programming
    Replies:
    0
    Views:
    285
    George2
    Mar 12, 2008
  4. James
    Replies:
    10
    Views:
    960
    Alf P. Steinbach
    Nov 28, 2009
  5. Igor R.
    Replies:
    9
    Views:
    524
    James Kanze
    Apr 6, 2010
Loading...

Share This Page