Isn't function resolution consistent?

Discussion in 'C++' started by DeMarcus, Apr 26, 2010.

  1. DeMarcus

    DeMarcus Guest

    Hi,

    Consider this example where A could be something similar to a home made
    std::eek:stream.

    class A
    {
    public:

    template<typename T>
    A& operator<<( const T& t )
    {
    std::cout << "Function Template" << std::endl;
    return *this;
    }
    };

    // Just some class.
    class B
    {
    };

    // Similar to printing B.
    A& operator<<( A& a, const B& b )
    {
    std::cout << "Non-member Function" << std::endl;
    return a;
    }

    int main()
    {
    A a;
    B b;

    a << b;
    }

    Now, if I run all this in the same file I get the output "Non-member
    function". But if I put class B and its operator<<() in a separate file
    I get the output "Function Template".

    Shouldn't the operator<< resolution be predictable? I want to run the
    non-member function if it exists, and the template function otherwise.
    How can I achieve that?


    Thanks,
    Daniel
    DeMarcus, Apr 26, 2010
    #1
    1. Advertising

  2. DeMarcus <> writes:

    > Hi,
    >
    > Consider this example where A could be something similar to a home
    > made std::eek:stream.
    >
    > class A
    > {
    > public:
    >
    > template<typename T>
    > A& operator<<( const T& t )
    > {
    > std::cout << "Function Template" << std::endl;
    > return *this;
    > }
    > };
    >
    > // Just some class.
    > class B
    > {
    > };
    >
    > // Similar to printing B.
    > A& operator<<( A& a, const B& b )
    > {
    > std::cout << "Non-member Function" << std::endl;
    > return a;
    > }
    >
    > int main()
    > {
    > A a;
    > B b;
    >
    > a << b;
    > }
    >
    > Now, if I run all this in the same file I get the output "Non-member
    > function". But if I put class B and its operator<<() in a separate
    > file I get the output "Function Template".
    >
    > Shouldn't the operator<< resolution be predictable? I want to run the
    > non-member function if it exists, and the template function
    > otherwise. How can I achieve that?


    I think that we would need to have information about just what you mean
    by "put class B and its operator<<() in a separate file." Reading the
    words as is suggests you are making two files where you had one. What
    is this second file? Source file (e.g., .cpp) or header (e.g., .hpp)?
    How is it integrated into the program you are building? Linked object
    file from source file or included header? Without this information
    there are too many possibilities as to how you might have achieved this,
    and potentially different outcomes in each (some) case(s).

    For instance, if we take your statement literally that you "put class B
    and its operator<<() in a separate file," how is your class A definition
    made available in that file in order to permit the definition of op<<?

    Regards

    Paul Bibbings
    Paul Bibbings, Apr 26, 2010
    #2
    1. Advertising

  3. DeMarcus

    DeMarcus Guest

    Paul Bibbings wrote:
    > DeMarcus <> writes:
    >
    >> Hi,
    >>
    >> Consider this example where A could be something similar to a home
    >> made std::eek:stream.
    >>
    >> class A
    >> {
    >> public:
    >>
    >> template<typename T>
    >> A& operator<<( const T& t )
    >> {
    >> std::cout << "Function Template" << std::endl;
    >> return *this;
    >> }
    >> };
    >>
    >> // Just some class.
    >> class B
    >> {
    >> };
    >>
    >> // Similar to printing B.
    >> A& operator<<( A& a, const B& b )
    >> {
    >> std::cout << "Non-member Function" << std::endl;
    >> return a;
    >> }
    >>
    >> int main()
    >> {
    >> A a;
    >> B b;
    >>
    >> a << b;
    >> }
    >>
    >> Now, if I run all this in the same file I get the output "Non-member
    >> function". But if I put class B and its operator<<() in a separate
    >> file I get the output "Function Template".
    >>
    >> Shouldn't the operator<< resolution be predictable? I want to run the
    >> non-member function if it exists, and the template function
    >> otherwise. How can I achieve that?

    >
    > I think that we would need to have information about just what you mean
    > by "put class B and its operator<<() in a separate file." Reading the
    > words as is suggests you are making two files where you had one. What
    > is this second file? Source file (e.g., .cpp) or header (e.g., .hpp)?
    > How is it integrated into the program you are building? Linked object
    > file from source file or included header? Without this information
    > there are too many possibilities as to how you might have achieved this,
    > and potentially different outcomes in each (some) case(s).
    >
    > For instance, if we take your statement literally that you "put class B
    > and its operator<<() in a separate file," how is your class A definition
    > made available in that file in order to permit the definition of op<<?
    >


    Apologies! I will better.
    Following setup gives me the different function resolution on gcc 4.4.1.

    // main.cpp
    #include "A.hpp"
    #include "B.hpp"
    int main()
    {
    A a;
    B b;
    a << b;
    }


    //A.hpp (with appropriate #ifndef A_HPP_)
    class A
    {
    public:

    template<typename T>
    A& operator<<( const T& t )
    {
    std::cout << "Function Template" << std::endl;
    return *this;
    }
    };


    // B.hpp (with appropriate #ifndef B_HPP_)
    class A;
    class B
    {
    };
    A& operator<<( A& a, const B& b );

    // B.cpp
    #include "B.hpp"
    #include "A.hpp"
    A& operator<<( A& a, const B& b )
    {
    std::cout << "Non-member Function" << std::endl;
    return a;
    }
    DeMarcus, Apr 26, 2010
    #3
  4. DeMarcus <> writes:

    > Paul Bibbings wrote:
    >> DeMarcus <> writes:
    >>
    >>> Hi,
    >>>
    >>> Consider this example where A could be something similar to a home
    >>> made std::eek:stream.
    >>>
    >>> class A
    >>> {
    >>> public:
    >>>
    >>> template<typename T>
    >>> A& operator<<( const T& t )
    >>> {
    >>> std::cout << "Function Template" << std::endl;
    >>> return *this;
    >>> }
    >>> };
    >>>
    >>> // Just some class.
    >>> class B
    >>> {
    >>> };
    >>>
    >>> // Similar to printing B.
    >>> A& operator<<( A& a, const B& b )
    >>> {
    >>> std::cout << "Non-member Function" << std::endl;
    >>> return a;
    >>> }
    >>>
    >>> int main()
    >>> {
    >>> A a;
    >>> B b;
    >>>
    >>> a << b;
    >>> }
    >>>
    >>> Now, if I run all this in the same file I get the output "Non-member
    >>> function". But if I put class B and its operator<<() in a separate
    >>> file I get the output "Function Template".
    >>>
    >>> Shouldn't the operator<< resolution be predictable? I want to run the
    >>> non-member function if it exists, and the template function
    >>> otherwise. How can I achieve that?

    >>
    >> I think that we would need to have information about just what you mean
    >> by "put class B and its operator<<() in a separate file." Reading the
    >> words as is suggests you are making two files where you had one. What
    >> is this second file? Source file (e.g., .cpp) or header (e.g., .hpp)?
    >> How is it integrated into the program you are building? Linked object
    >> file from source file or included header? Without this information
    >> there are too many possibilities as to how you might have achieved this,
    >> and potentially different outcomes in each (some) case(s).
    >>
    >> For instance, if we take your statement literally that you "put class B
    >> and its operator<<() in a separate file," how is your class A definition
    >> made available in that file in order to permit the definition of op<<?
    >>

    >
    > Apologies! I will better.
    > Following setup gives me the different function resolution on gcc 4.4.1.
    >
    > // main.cpp
    > #include "A.hpp"
    > #include "B.hpp"
    > int main()
    > {
    > A a;
    > B b;
    > a << b;
    > }
    >
    >
    > //A.hpp (with appropriate #ifndef A_HPP_)
    > class A
    > {
    > public:
    >
    > template<typename T>
    > A& operator<<( const T& t )
    > {
    > std::cout << "Function Template" << std::endl;
    > return *this;
    > }
    > };
    >
    >
    > // B.hpp (with appropriate #ifndef B_HPP_)
    > class A;
    > class B
    > {
    > };
    > A& operator<<( A& a, const B& b );
    >
    > // B.cpp
    > #include "B.hpp"
    > #include "A.hpp"
    > A& operator<<( A& a, const B& b )
    > {
    > std::cout << "Non-member Function" << std::endl;
    > return a;
    > }


    Thanks for clarifying that. The thing is, after adding only the missing
    include guards and <iostream> header, I am not getting the same results
    as you (see below).

    ==First Try==

    12:53:11 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat AB.cpp
    // file: AB.cpp

    #include <iostream>

    class A
    {
    public:

    template<typename T>
    A& operator<<( const T& t )
    {
    std::cout << "Function Template" << std::endl;
    return *this;
    }
    };

    // Just some class.
    class B
    {
    };

    // Similar to printing B.
    A& operator<<( A& a, const B& b )
    {
    std::cout << "Non-member Function" << std::endl;
    return a;
    }

    int main()
    {
    A a;
    B b;

    a << b;
    }

    12:59:07 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    $i686-pc-cygwin-g++-4.4.1 -o AB AB.cpp

    12:59:57 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $./AB
    Non-member Function
    ^^^^^^^^^^^^^^^^^^^


    ==Second Try==

    13:06:10 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat A.hpp
    // file: A.hpp

    #ifndef A_HPP_
    #define A_HPP_

    #include <iostream>

    class A
    {
    public:

    template<typename T>
    A& operator<<( const T& t )
    {
    std::cout << "Function Template" << std::endl;
    return *this;
    }
    };

    #endif /* A_HPP_ */

    13:06:19 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat B.hpp
    // file: B.hpp

    #ifndef B_HPP_
    #define B_HPP_

    class A;
    class B
    {
    };
    A& operator<<( A& a, const B& b );

    #endif /* B_HPP_ */


    13:06:23 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat B.cpp
    // file: B.cpp

    #include "B.hpp"
    #include "A.hpp"

    A& operator<<( A& a, const B& b )
    {
    std::cout << "Non-member Function" << std::endl;
    return a;
    }

    13:06:27 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat main.cpp
    // file: main.cpp

    #include "A.hpp"
    #include "B.hpp"
    int main()
    {
    A a;
    B b;
    a << b;
    }



    13:06:32 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    $i686-pc-cygwin-g++-4.4.1 -o AB2 main.cpp B.cpp

    13:15:55 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $./AB2
    Non-member Function
    ^^^^^^^^^^^^^^^^^^^

    Regards

    Paul Bibbings
    Paul Bibbings, Apr 27, 2010
    #4
  5. DeMarcus

    John H. Guest

    On Apr 27, 7:29 am, Paul Bibbings <> wrote:
    > The thing is ... I am not getting the same results
    > as you


    I also tried this on VS2010 and g++4.3.4 and my results were like
    those of Mr. Bibbings: it resolved to the free standing version when
    available.
    John H., Apr 27, 2010
    #5
  6. DeMarcus

    DeMarcus Guest

    Paul Bibbings wrote:
    > DeMarcus <> writes:
    >
    >> Paul Bibbings wrote:
    >>> DeMarcus <> writes:
    >>>
    >>>> Hi,
    >>>>
    >>>> Consider this example where A could be something similar to a home
    >>>> made std::eek:stream.
    >>>>
    >>>> class A
    >>>> {
    >>>> public:
    >>>>
    >>>> template<typename T>
    >>>> A& operator<<( const T& t )
    >>>> {
    >>>> std::cout << "Function Template" << std::endl;
    >>>> return *this;
    >>>> }
    >>>> };
    >>>>
    >>>> // Just some class.
    >>>> class B
    >>>> {
    >>>> };
    >>>>
    >>>> // Similar to printing B.
    >>>> A& operator<<( A& a, const B& b )
    >>>> {
    >>>> std::cout << "Non-member Function" << std::endl;
    >>>> return a;
    >>>> }
    >>>>
    >>>> int main()
    >>>> {
    >>>> A a;
    >>>> B b;
    >>>>
    >>>> a << b;
    >>>> }
    >>>>
    >>>> Now, if I run all this in the same file I get the output "Non-member
    >>>> function". But if I put class B and its operator<<() in a separate
    >>>> file I get the output "Function Template".
    >>>>
    >>>> Shouldn't the operator<< resolution be predictable? I want to run the
    >>>> non-member function if it exists, and the template function
    >>>> otherwise. How can I achieve that?
    >>> I think that we would need to have information about just what you mean
    >>> by "put class B and its operator<<() in a separate file." Reading the
    >>> words as is suggests you are making two files where you had one. What
    >>> is this second file? Source file (e.g., .cpp) or header (e.g., .hpp)?
    >>> How is it integrated into the program you are building? Linked object
    >>> file from source file or included header? Without this information
    >>> there are too many possibilities as to how you might have achieved this,
    >>> and potentially different outcomes in each (some) case(s).
    >>>
    >>> For instance, if we take your statement literally that you "put class B
    >>> and its operator<<() in a separate file," how is your class A definition
    >>> made available in that file in order to permit the definition of op<<?
    >>>

    >> Apologies! I will better.
    >> Following setup gives me the different function resolution on gcc 4.4.1.
    >>
    >> // main.cpp
    >> #include "A.hpp"
    >> #include "B.hpp"
    >> int main()
    >> {
    >> A a;
    >> B b;
    >> a << b;
    >> }
    >>
    >>
    >> //A.hpp (with appropriate #ifndef A_HPP_)
    >> class A
    >> {
    >> public:
    >>
    >> template<typename T>
    >> A& operator<<( const T& t )
    >> {
    >> std::cout << "Function Template" << std::endl;
    >> return *this;
    >> }
    >> };
    >>
    >>
    >> // B.hpp (with appropriate #ifndef B_HPP_)
    >> class A;
    >> class B
    >> {
    >> };
    >> A& operator<<( A& a, const B& b );
    >>
    >> // B.cpp
    >> #include "B.hpp"
    >> #include "A.hpp"
    >> A& operator<<( A& a, const B& b )
    >> {
    >> std::cout << "Non-member Function" << std::endl;
    >> return a;
    >> }

    >
    > Thanks for clarifying that. The thing is, after adding only the missing
    > include guards and <iostream> header, I am not getting the same results
    > as you (see below).
    >
    > ==First Try==
    >
    > 12:53:11 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat AB.cpp
    > // file: AB.cpp
    >
    > #include <iostream>
    >
    > class A
    > {
    > public:
    >
    > template<typename T>
    > A& operator<<( const T& t )
    > {
    > std::cout << "Function Template" << std::endl;
    > return *this;
    > }
    > };
    >
    > // Just some class.
    > class B
    > {
    > };
    >
    > // Similar to printing B.
    > A& operator<<( A& a, const B& b )
    > {
    > std::cout << "Non-member Function" << std::endl;
    > return a;
    > }
    >
    > int main()
    > {
    > A a;
    > B b;
    >
    > a << b;
    > }
    >
    > 12:59:07 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    > $i686-pc-cygwin-g++-4.4.1 -o AB AB.cpp
    >
    > 12:59:57 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $./AB
    > Non-member Function
    > ^^^^^^^^^^^^^^^^^^^
    >
    >
    > ==Second Try==
    >
    > 13:06:10 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat A.hpp
    > // file: A.hpp
    >
    > #ifndef A_HPP_
    > #define A_HPP_
    >
    > #include <iostream>
    >
    > class A
    > {
    > public:
    >
    > template<typename T>
    > A& operator<<( const T& t )
    > {
    > std::cout << "Function Template" << std::endl;
    > return *this;
    > }
    > };
    >
    > #endif /* A_HPP_ */
    >
    > 13:06:19 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat B.hpp
    > // file: B.hpp
    >
    > #ifndef B_HPP_
    > #define B_HPP_
    >
    > class A;
    > class B
    > {
    > };
    > A& operator<<( A& a, const B& b );
    >
    > #endif /* B_HPP_ */
    >
    >
    > 13:06:23 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat B.cpp
    > // file: B.cpp
    >
    > #include "B.hpp"
    > #include "A.hpp"
    >
    > A& operator<<( A& a, const B& b )
    > {
    > std::cout << "Non-member Function" << std::endl;
    > return a;
    > }
    >
    > 13:06:27 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat main.cpp
    > // file: main.cpp
    >
    > #include "A.hpp"
    > #include "B.hpp"
    > int main()
    > {
    > A a;
    > B b;
    > a << b;
    > }
    >
    >
    >
    > 13:06:32 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    > $i686-pc-cygwin-g++-4.4.1 -o AB2 main.cpp B.cpp
    >
    > 13:15:55 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $./AB2
    > Non-member Function
    > ^^^^^^^^^^^^^^^^^^^
    >
    > Regards
    >
    > Paul Bibbings


    Yes, but now comes the strange part. Let's change main.cpp slightly to
    the following.

    // file: main.cpp
    #include "A.hpp"
    #include "B.hpp"

    void fnc( const A& a )
    {
    }

    int main()
    {
    B b;
    fnc( A() << b );
    }

    Now it prints "Function Template". Why?
    DeMarcus, Apr 28, 2010
    #6
  7. DeMarcus

    DeMarcus Guest

    DeMarcus wrote:
    > Paul Bibbings wrote:
    >> DeMarcus <> writes:
    >>
    >>> Paul Bibbings wrote:
    >>>> DeMarcus <> writes:
    >>>>
    >>>>> Hi,
    >>>>>
    >>>>> Consider this example where A could be something similar to a home
    >>>>> made std::eek:stream.
    >>>>>
    >>>>> class A
    >>>>> {
    >>>>> public:
    >>>>>
    >>>>> template<typename T>
    >>>>> A& operator<<( const T& t )
    >>>>> {
    >>>>> std::cout << "Function Template" << std::endl;
    >>>>> return *this;
    >>>>> }
    >>>>> };
    >>>>>
    >>>>> // Just some class.
    >>>>> class B
    >>>>> {
    >>>>> };
    >>>>>
    >>>>> // Similar to printing B.
    >>>>> A& operator<<( A& a, const B& b )
    >>>>> {
    >>>>> std::cout << "Non-member Function" << std::endl;
    >>>>> return a;
    >>>>> }
    >>>>>
    >>>>> int main()
    >>>>> {
    >>>>> A a;
    >>>>> B b;
    >>>>>
    >>>>> a << b;
    >>>>> }
    >>>>>
    >>>>> Now, if I run all this in the same file I get the output "Non-member
    >>>>> function". But if I put class B and its operator<<() in a separate
    >>>>> file I get the output "Function Template".
    >>>>>
    >>>>> Shouldn't the operator<< resolution be predictable? I want to run the
    >>>>> non-member function if it exists, and the template function
    >>>>> otherwise. How can I achieve that?
    >>>> I think that we would need to have information about just what you mean
    >>>> by "put class B and its operator<<() in a separate file." Reading the
    >>>> words as is suggests you are making two files where you had one. What
    >>>> is this second file? Source file (e.g., .cpp) or header (e.g., .hpp)?
    >>>> How is it integrated into the program you are building? Linked object
    >>>> file from source file or included header? Without this information
    >>>> there are too many possibilities as to how you might have achieved
    >>>> this,
    >>>> and potentially different outcomes in each (some) case(s).
    >>>>
    >>>> For instance, if we take your statement literally that you "put class B
    >>>> and its operator<<() in a separate file," how is your class A
    >>>> definition
    >>>> made available in that file in order to permit the definition of op<<?
    >>>>
    >>> Apologies! I will better.
    >>> Following setup gives me the different function resolution on gcc 4.4.1.
    >>>
    >>> // main.cpp
    >>> #include "A.hpp"
    >>> #include "B.hpp"
    >>> int main()
    >>> {
    >>> A a;
    >>> B b;
    >>> a << b;
    >>> }
    >>>
    >>>
    >>> //A.hpp (with appropriate #ifndef A_HPP_)
    >>> class A
    >>> {
    >>> public:
    >>>
    >>> template<typename T>
    >>> A& operator<<( const T& t )
    >>> {
    >>> std::cout << "Function Template" << std::endl;
    >>> return *this;
    >>> }
    >>> };
    >>>
    >>>
    >>> // B.hpp (with appropriate #ifndef B_HPP_)
    >>> class A;
    >>> class B
    >>> {
    >>> };
    >>> A& operator<<( A& a, const B& b );
    >>>
    >>> // B.cpp
    >>> #include "B.hpp"
    >>> #include "A.hpp"
    >>> A& operator<<( A& a, const B& b )
    >>> {
    >>> std::cout << "Non-member Function" << std::endl;
    >>> return a;
    >>> }

    >>
    >> Thanks for clarifying that. The thing is, after adding only the missing
    >> include guards and <iostream> header, I am not getting the same results
    >> as you (see below).
    >>
    >> ==First Try==
    >>
    >> 12:53:11 Paul Bibbings@JIJOU
    >> /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat AB.cpp
    >> // file: AB.cpp
    >>
    >> #include <iostream>
    >>
    >> class A
    >> {
    >> public:
    >>
    >> template<typename T>
    >> A& operator<<( const T& t )
    >> {
    >> std::cout << "Function Template" << std::endl;
    >> return *this;
    >> }
    >> };
    >>
    >> // Just some class.
    >> class B
    >> {
    >> };
    >>
    >> // Similar to printing B.
    >> A& operator<<( A& a, const B& b )
    >> {
    >> std::cout << "Non-member Function" << std::endl;
    >> return a;
    >> }
    >>
    >> int main()
    >> {
    >> A a;
    >> B b;
    >>
    >> a << b;
    >> }
    >>
    >> 12:59:07 Paul Bibbings@JIJOU
    >> /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    >> $i686-pc-cygwin-g++-4.4.1 -o AB AB.cpp
    >> 12:59:57 Paul Bibbings@JIJOU
    >> /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $./AB
    >> Non-member Function
    >> ^^^^^^^^^^^^^^^^^^^
    >>
    >>
    >> ==Second Try==
    >>
    >> 13:06:10 Paul Bibbings@JIJOU
    >> /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat A.hpp
    >> // file: A.hpp
    >>
    >> #ifndef A_HPP_
    >> #define A_HPP_
    >>
    >> #include <iostream>
    >>
    >> class A
    >> {
    >> public:
    >>
    >> template<typename T>
    >> A& operator<<( const T& t )
    >> {
    >> std::cout << "Function Template" << std::endl;
    >> return *this;
    >> }
    >> };
    >>
    >> #endif /* A_HPP_ */
    >>
    >> 13:06:19 Paul Bibbings@JIJOU
    >> /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat B.hpp
    >> // file: B.hpp
    >>
    >> #ifndef B_HPP_
    >> #define B_HPP_
    >>
    >> class A;
    >> class B
    >> {
    >> };
    >> A& operator<<( A& a, const B& b );
    >>
    >> #endif /* B_HPP_ */
    >>
    >>
    >> 13:06:23 Paul Bibbings@JIJOU
    >> /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat B.cpp
    >> // file: B.cpp
    >>
    >> #include "B.hpp"
    >> #include "A.hpp"
    >>
    >> A& operator<<( A& a, const B& b )
    >> {
    >> std::cout << "Non-member Function" << std::endl;
    >> return a;
    >> }
    >>
    >> 13:06:27 Paul Bibbings@JIJOU
    >> /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat main.cpp
    >> // file: main.cpp
    >>
    >> #include "A.hpp"
    >> #include "B.hpp"
    >> int main()
    >> {
    >> A a;
    >> B b;
    >> a << b;
    >> }
    >>
    >>
    >>
    >> 13:06:32 Paul Bibbings@JIJOU
    >> /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    >> $i686-pc-cygwin-g++-4.4.1 -o AB2 main.cpp B.cpp
    >> 13:15:55 Paul Bibbings@JIJOU
    >> /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $./AB2
    >> Non-member Function
    >> ^^^^^^^^^^^^^^^^^^^
    >>
    >> Regards
    >>
    >> Paul Bibbings

    >
    > Yes, but now comes the strange part. Let's change main.cpp slightly to
    > the following.
    >
    > // file: main.cpp
    > #include "A.hpp"
    > #include "B.hpp"
    >
    > void fnc( const A& a )
    > {
    > }
    >
    > int main()
    > {
    > B b;
    > fnc( A() << b );
    > }
    >
    > Now it prints "Function Template". Why?
    >
    >


    A more illustrating example is actually the following.

    // file: main.cpp
    #include "A.hpp"
    #include "B.hpp"

    int main()
    {
    A a;
    B b;

    a << b;
    A() << b;
    }
    DeMarcus, Apr 28, 2010
    #7
  8. DeMarcus <> writes:


    > Yes, but now comes the strange part. Let's change main.cpp slightly to
    > the following.
    >
    > // file: main.cpp
    > #include "A.hpp"
    > #include "B.hpp"
    >
    > void fnc( const A& a )
    > {
    > }
    >
    > int main()
    > {
    > B b;
    > fnc( A() << b );
    > }
    >
    > Now it prints "Function Template". Why?


    Okay. It seems that we now come to the /real/ source of why you were not
    getting the results you expected, but this was not part of your original
    specification, so the journey here was a little around the issue.

    Using all the code we have so far and merely making this change in main,
    the first thing to note is that your A() in the expression A() << b is
    now an rvalue, whereas before it was an lvalue. This cannot bind to the
    first parameter of the non-member function:

    A& operator<<(A& a, const B& b);

    Here is the problem in isolation:

    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat call_with_rvalue.cpp
    // file: call_with_rvalue.cpp

    class A { };
    class B { };

    A& operator<<(A& a, const B& b) { }

    int main()
    {
    B b;
    A() << b;
    }


    09:32:25 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    $i686-pc-cygwin-gcc-4.4.1 -c call_with_rvalue.cpp
    call_with_rvalue.cpp: In function 'int main()':
    call_with_rvalue.cpp:11: error: no match for 'operator<<' in 'A() << b'
    call_with_rvalue.cpp:6: note: candidates are: A& operator<<(A&, const B&)

    So, as you can see, it's not an issue about how the code is structured
    after all, but rather with the *extra* change of using an rvalue in the
    invocation over an lvalue in the original code. The non-member function
    is not, in this instance, ignored because the member function is
    suddenly preferred; rather it is that, with this change, the non-member
    function is no longer viable.

    Related to this, we have here a good illustration of why it is important
    to post the *precise* code that causes the problem from the outset.
    Investigations have gone round a long route only to find that the cause
    originated from some aspect of the code that was only "pulled out of the hat"
    at the last minute. We would have reached the solution immediately, had
    we had this information from the beginning.

    Regards

    Paul Bibbings
    Paul Bibbings, Apr 28, 2010
    #8
  9. DeMarcus

    tonydee Guest

    > #include "A.hpp"
    > #include "B.hpp"
    >
    > int main()
    > {
    >     A a;
    >     B b;
    >
    >     a << b;
    >     A() << b;
    >
    > }


    Sorry, I haven't bothered to read through all of this - you're using
    an MS compiler I don't have handy anyway - but if this is a "more
    illustrating" example of anything, then it can only be that a << b and
    A() << b don't produce the same result. Perhaps your issue is that
    operator<< takes an A by (non-const) reference, which won't be
    selected for the temporary...?

    Cheers,
    Tony
    tonydee, Apr 28, 2010
    #9
  10. DeMarcus

    DeMarcus Guest

    Paul Bibbings wrote:
    > DeMarcus <> writes:
    >
    >
    >> Yes, but now comes the strange part. Let's change main.cpp slightly to
    >> the following.
    >>
    >> // file: main.cpp
    >> #include "A.hpp"
    >> #include "B.hpp"
    >>
    >> void fnc( const A& a )
    >> {
    >> }
    >>
    >> int main()
    >> {
    >> B b;
    >> fnc( A() << b );
    >> }
    >>
    >> Now it prints "Function Template". Why?

    >
    > Okay. It seems that we now come to the /real/ source of why you were not
    > getting the results you expected, but this was not part of your original
    > specification, so the journey here was a little around the issue.
    >
    > Using all the code we have so far and merely making this change in main,
    > the first thing to note is that your A() in the expression A() << b is
    > now an rvalue, whereas before it was an lvalue. This cannot bind to the
    > first parameter of the non-member function:
    >
    > A& operator<<(A& a, const B& b);
    >
    > Here is the problem in isolation:
    >
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat call_with_rvalue.cpp
    > // file: call_with_rvalue.cpp
    >
    > class A { };
    > class B { };
    >
    > A& operator<<(A& a, const B& b) { }
    >
    > int main()
    > {
    > B b;
    > A() << b;
    > }
    >
    >
    > 09:32:25 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    > $i686-pc-cygwin-gcc-4.4.1 -c call_with_rvalue.cpp
    > call_with_rvalue.cpp: In function 'int main()':
    > call_with_rvalue.cpp:11: error: no match for 'operator<<' in 'A() << b'
    > call_with_rvalue.cpp:6: note: candidates are: A& operator<<(A&, const B&)
    >
    > So, as you can see, it's not an issue about how the code is structured
    > after all, but rather with the *extra* change of using an rvalue in the
    > invocation over an lvalue in the original code. The non-member function
    > is not, in this instance, ignored because the member function is
    > suddenly preferred; rather it is that, with this change, the non-member
    > function is no longer viable.
    >
    > Related to this, we have here a good illustration of why it is important
    > to post the *precise* code that causes the problem from the outset.
    > Investigations have gone round a long route only to find that the cause
    > originated from some aspect of the code that was only "pulled out of the hat"
    > at the last minute. We would have reached the solution immediately, had
    > we had this information from the beginning.
    >
    > Regards
    >
    > Paul Bibbings


    I try to get to the point as quick as possible, however, it would be
    impossible for me (and the reader) to post all source code. Therefore I
    tried to pull out the smallest example but realized I missed the
    important thing with the rvalue.

    Here's a relevant follow-up question. When C++0x comes, shall we change
    all the print operators from

    std::eek:stream& operator<<( std::eek:stream& s, const SomeClass& sc );

    to

    std::eek:stream& operator<<( std::eek:stream&& s, const SomeClass& sc );

    since the rvalue reference will catch both
    a << b;
    and
    A() << b;

    Or will there be other complications doing that change?
    DeMarcus, Apr 28, 2010
    #10
  11. DeMarcus <> writes:

    > Here's a relevant follow-up question. When C++0x comes, shall we
    > change all the print operators from
    >
    > std::eek:stream& operator<<( std::eek:stream& s, const SomeClass& sc );
    >
    > to
    >
    > std::eek:stream& operator<<( std::eek:stream&& s, const SomeClass& sc );


    Did you perhaps intend this second to be:

    std::eek:stream& operator<<(std::eek:stream& s, const SomeClass&& sc ); ?

    The first parameter will need to remain std::eek:stream&, or otherwise you
    are attempting to create an rvalue-reference temporary to the stream
    object which is surely not what you intend.
    >
    > since the rvalue reference will catch both
    > a << b;
    > and
    > A() << b;
    >
    > Or will there be other complications doing that change?


    I'm a little confused by this, since your usage:

    a << b; and A() << b;

    refers to your own overloaded op<<'s, which don't match the signature
    of the `conventional' op<< that you give the declaration for above. You
    appear to be mixing the two in your question.

    As to the first (though I appreciate this may not be what you are
    asking), there is no need to change the parameter types to rvalue
    references, as the following example illustrates:

    11:21:27 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat cpp0x_ex.cpp
    // file: cpp0x_ex.cpp

    #include <iostream>

    class SomeClass { };

    std::eek:stream& operator<<(std::eek:stream& s, const SomeClass& sc)
    {
    return s << "op<<";
    }

    int main()
    {
    SomeClass sc;

    std::cout << sc; // lvalue
    std::cout << SomeClass(); // rvalue
    std::cout << std::move(sc); // rvalue reference
    }


    11:21:36 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    $i686-pc-cygwin-gcc-4.5.0 -std=c++0x -c cpp0x_ex.cpp

    11:22:04 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    $i686-pc-cygwin-g++-4.5.0 -o cpp0x_ex cpp0x_ex.o

    11:27:07 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $./cpp0x_ex
    op<<op<<op<<

    The key here (in a sense) is the const on the second parameter, which
    evidently permits all these combinations.

    Regards

    Paul Bibbings
    Paul Bibbings, Apr 28, 2010
    #11
  12. DeMarcus <> writes:

    > I try to get to the point as quick as possible, however, it would be
    > impossible for me (and the reader) to post all source code. Therefore
    > I tried to pull out the smallest example but realized I missed the
    > important thing with the rvalue.


    It can be very hard when you are attempting to pull out the smallest
    example from a large section of code in this way. I think that the most
    important goals in doing so, however, include the following:

    1) The code must compile, or be sufficient to send to a compiler
    without additions. (Note: by this I don't mean that it should
    compile /successfully/, but where it doesn't it must only fail in
    the same way that you have experienced it to fail.)

    2) The code must, when compiled and perhaps run, illustrate the
    /actual/ problem you are having.

    Without intending to be overly critical, your early examples were
    incomplete in sense 1) and required additions and assumptions to get
    something to send to the compiler and then, when clarified, didn't
    illustrate the actual problem you were experiencing in the sense of 2).

    It is such considerations that are the challenge of reducing a large
    program to a small example that isolates the issue. Sometimes this is a
    significantly difficult task, but in my experience is worth doing not
    only because it helps people to help you quickly.

    If the condensing is done in this way then it helps /you/, the
    programmer, focus on where the issue actually originates in your code.
    In having to make the example as small as possible, yet still retain the
    problem, you are in one sense actually `debugging' your own code. Often
    the results of this process are that you actually discover the problem
    for yourself, and I would say that in my own experience, whenever I
    attempt to produce this kind of minimal, yet complete, example for
    posting a question on usenet, only around 1 in 5 actually end up here.
    For the others, the solution becomes `obvious' simply through having
    gone through the process of localizing the problem in my code and
    focussing on as small an example as I can get that still illustrates
    it.

    Regards

    Paul Bibbings
    Paul Bibbings, Apr 28, 2010
    #12
  13. DeMarcus

    DeMarcus Guest

    Paul Bibbings wrote:
    > DeMarcus <> writes:
    >
    >> Here's a relevant follow-up question. When C++0x comes, shall we
    >> change all the print operators from
    >>
    >> std::eek:stream& operator<<( std::eek:stream& s, const SomeClass& sc );
    >>
    >> to
    >>
    >> std::eek:stream& operator<<( std::eek:stream&& s, const SomeClass& sc );

    >
    > Did you perhaps intend this second to be:
    >
    > std::eek:stream& operator<<(std::eek:stream& s, const SomeClass&& sc ); ?
    >


    No, I meant exactly what I wrote this time. ;)

    I want to do this:

    fnc( const A& a );

    int main()
    {
    B b;
    fnc( A() << b );
    }

    ....and still have my non-member function invoked. It works if I do this:

    A& operator<<( A&& a, const B& b );

    > The first parameter will need to remain std::eek:stream&, or otherwise you
    > are attempting to create an rvalue-reference temporary to the stream
    > object which is surely not what you intend.


    I just intend to call the non-member function for both
    A() << b;
    and
    a << b;

    In
    A& operator<<( A&& a, const B& b );
    will A&& do something with what's input there? I've read somewhere that
    rvalue references will be used for move semantics. Would anything input
    here be moved?


    >> since the rvalue reference will catch both
    >> a << b;
    >> and
    >> A() << b;
    >>
    >> Or will there be other complications doing that change?

    >
    > I'm a little confused by this, since your usage:
    >
    > a << b; and A() << b;
    >
    > refers to your own overloaded op<<'s, which don't match the signature
    > of the `conventional' op<< that you give the declaration for above. You
    > appear to be mixing the two in your question.
    >


    I'm doing my own kind of stream called A. But I want it to be as similar
    to std::eek:stream as possible.

    > As to the first (though I appreciate this may not be what you are
    > asking), there is no need to change the parameter types to rvalue
    > references, as the following example illustrates:
    >
    > 11:21:27 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat cpp0x_ex.cpp
    > // file: cpp0x_ex.cpp
    >
    > #include <iostream>
    >
    > class SomeClass { };
    >
    > std::eek:stream& operator<<(std::eek:stream& s, const SomeClass& sc)
    > {
    > return s << "op<<";
    > }
    >
    > int main()
    > {
    > SomeClass sc;
    >
    > std::cout << sc; // lvalue
    > std::cout << SomeClass(); // rvalue
    > std::cout << std::move(sc); // rvalue reference
    > }
    >
    >
    > 11:21:36 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    > $i686-pc-cygwin-gcc-4.5.0 -std=c++0x -c cpp0x_ex.cpp
    >
    > 11:22:04 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    > $i686-pc-cygwin-g++-4.5.0 -o cpp0x_ex cpp0x_ex.o
    >
    > 11:27:07 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $./cpp0x_ex
    > op<<op<<op<<
    >
    > The key here (in a sense) is the const on the second parameter, which
    > evidently permits all these combinations.
    >


    Yes, but in my case the ostream may be an rvalue, like this.

    void print( const std::eek:stream& s )
    {
    std::cout << s.rdbuf() << std::endl;
    }

    int main()
    {
    SomeClass sc;
    print( std::stringstream() << sc );
    }

    therefore I need to define the operator like this

    std::eek:stream& operator<<( std::eek:stream&& s, const SomeClass& sc );

    or will the rvalue reference do something bad with the stream if I use a
    classic output like the following?

    std::cout << SomeClass();
    DeMarcus, Apr 28, 2010
    #13
  14. DeMarcus

    DeMarcus Guest

    Paul Bibbings wrote:
    > DeMarcus <> writes:
    >
    >> I try to get to the point as quick as possible, however, it would be
    >> impossible for me (and the reader) to post all source code. Therefore
    >> I tried to pull out the smallest example but realized I missed the
    >> important thing with the rvalue.

    >
    > It can be very hard when you are attempting to pull out the smallest
    > example from a large section of code in this way. I think that the most
    > important goals in doing so, however, include the following:
    >
    > 1) The code must compile, or be sufficient to send to a compiler
    > without additions. (Note: by this I don't mean that it should
    > compile /successfully/, but where it doesn't it must only fail in
    > the same way that you have experienced it to fail.)
    >
    > 2) The code must, when compiled and perhaps run, illustrate the
    > /actual/ problem you are having.
    >
    > Without intending to be overly critical, your early examples were
    > incomplete in sense 1) and required additions and assumptions to get
    > something to send to the compiler and then, when clarified, didn't
    > illustrate the actual problem you were experiencing in the sense of 2).
    >
    > It is such considerations that are the challenge of reducing a large
    > program to a small example that isolates the issue. Sometimes this is a
    > significantly difficult task, but in my experience is worth doing not
    > only because it helps people to help you quickly.
    >
    > If the condensing is done in this way then it helps /you/, the
    > programmer, focus on where the issue actually originates in your code.
    > In having to make the example as small as possible, yet still retain the
    > problem, you are in one sense actually `debugging' your own code. Often
    > the results of this process are that you actually discover the problem
    > for yourself, and I would say that in my own experience, whenever I
    > attempt to produce this kind of minimal, yet complete, example for
    > posting a question on usenet, only around 1 in 5 actually end up here.
    > For the others, the solution becomes `obvious' simply through having
    > gone through the process of localizing the problem in my code and
    > focussing on as small an example as I can get that still illustrates
    > it.
    >
    > Regards
    >
    > Paul Bibbings
    >


    Yes, you are right. I'll post more tested code in the future.
    DeMarcus, Apr 28, 2010
    #14
  15. DeMarcus <> writes:

    <snip />

    > No, I meant exactly what I wrote this time. ;)
    >
    > I want to do this:
    >
    > fnc( const A& a );
    >
    > int main()
    > {
    > B b;
    > fnc( A() << b );
    > }
    >
    > ...and still have my non-member function invoked. It works if I do this:
    >
    > A& operator<<( A&& a, const B& b );


    Okay. I'm getting a better sense of this now.

    <snip />

    > I just intend to call the non-member function for both
    > A() << b;
    > and
    > a << b;
    >
    > In
    > A& operator<<( A&& a, const B& b );
    > will A&& do something with what's input there? I've read somewhere
    > that rvalue references will be used for move semantics. Would anything
    > input here be moved?


    rvalue references are, of course, suitable for use in implementing move
    semantics, but not of themselves. They require support from code that
    uses them, such as a move constructor or move assignment operator. If
    your code inside the definition of your op<< does not involve any such
    things, then actual moving doesn't have to occur. But, see below.

    <snip />

    > I'm doing my own kind of stream called A. But I want it to be as
    > similar to std::eek:stream as possible.
    >


    So this is your wider purpose. In this case, whilst it seems we have
    reached a sense of what will make your original ideas `work', I think I
    would want to question those ideas. If we compare your op<< to the
    conventional declaration:

    std::eek:stream& operator<<(std::eek:stream&, const SomeObject&)

    I think that the reference on the first parameter is central to the
    design. Implemented in this way there is no copying of the stream
    object, and the same is the case into the return value. This permits
    chaining of the form:

    std::cout << anObject << anotherObject << yetAnotherObject;

    into the *same* stream.

    If you are going to allow use of your `stream' utilizing temporaries
    formed by A(), then you are essentially breaking the `model'. If you
    implement it as:

    A& operator<<(A&&, const B&)

    then you're going to be running into a few problems. Firstly, with this
    you are returning a reference to a temporary that has no existence after
    the call. So, you would have to adjust and not return a reference, say:

    A&& operator<<(A&&, const B&)

    But then, your chaining wouldn't work in the same way, and

    A() << aB << anotherB << yetAnotherB;

    would involve a succession of distinct temporary instances of A.

    All in all I think that I would want to steer away from permitting the
    use of temporary instances of your stream class in this way, which would
    in turn remove the original issue of having to consider adjustments just
    to get your free op<< to be called in all valid scenarios.

    <snip />

    Regards

    Paul Bibbings
    Paul Bibbings, Apr 28, 2010
    #15
  16. DeMarcus

    DeMarcus Guest

    > If you are going to allow use of your `stream' utilizing temporaries
    > formed by A(), then you are essentially breaking the `model'. If you
    > implement it as:
    >
    > A& operator<<(A&&, const B&)
    >
    > then you're going to be running into a few problems. Firstly, with this
    > you are returning a reference to a temporary that has no existence after
    > the call.


    Yes, but as far as I remember, the temporary should live the whole
    full-expression, i.e. the whole chaining. Nevertheless, I feel a bit
    uneasy returning a reference to an rvalue reference.


    > So, you would have to adjust and not return a reference, say:
    >
    > A&& operator<<(A&&, const B&)
    >
    > But then, your chaining wouldn't work in the same way,


    A first test with

    A&& operator<<( A&&, const B& );

    showed it seems to work as I expected(!?)

    > and
    >
    > A() << aB << anotherB << yetAnotherB;
    >
    > would involve a succession of distinct temporary instances of A.
    >


    But if implement it like this:

    A&& operator<<( A&& a, const B& b )
    {
    return a << "B";
    }

    then it should be the A() temporary only and not distinct ones, right?
    (since I return a)


    It seems that what I'm trading is the possibility of using the following.

    int main()
    {
    A a; B b;
    fnc( a << b );
    }

    fnc( A& a ); // won't work any more

    as well as having a slightly more nasty problem

    fnc( A&& a ); // possibly doing some unwanted move on lvalues
    DeMarcus, Apr 28, 2010
    #16
  17. DeMarcus

    DeMarcus Guest

    > So, you would have to adjust and not return a reference, say:
    >
    > A&& operator<<(A&&, const B&)
    >
    > But then, your chaining wouldn't work in the same way, and
    >
    > A() << aB << anotherB << yetAnotherB;
    >
    > would involve a succession of distinct temporary instances of A.
    >


    I solved it! I think. How about this in A.hpp?

    template<typename T>
    inline A&& operator<<( A&& a, const T& t )
    {
    std::cout << "Delegating..." << std::endl;
    return operator<<( a, t );
    }

    Or for the standard committee... ;)

    namespace std
    {

    template<typename T>
    inline std::eek:stream&& operator<<( std::eek:stream&& s, const T& t )
    {
    return operator<<( s, t );
    }

    }
    DeMarcus, Apr 28, 2010
    #17
  18. DeMarcus <> writes:

    >> If you are going to allow use of your `stream' utilizing temporaries
    >> formed by A(), then you are essentially breaking the `model'. If you
    >> implement it as:
    >>
    >> A& operator<<(A&&, const B&)
    >>
    >> then you're going to be running into a few problems. Firstly, with this
    >> you are returning a reference to a temporary that has no existence after
    >> the call.

    >
    > Yes, but as far as I remember, the temporary should live the whole
    > full-expression, i.e. the whole chaining.


    I would need to look into the detail as I'm a little hazy on whether
    that would be the case or not. However, there are other issues here.
    One is that chaining is not actually even possible with the above
    signature, since the return of an lvalue ref prevents the second
    invocation in the chain since the argument is not now an rvalue any
    more.

    14:33:46 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat
    ret_by_ref.cpp
    // file: ret_by_ref.cpp

    #include <iostream>

    class A { };
    class B { };

    A& operator<<(A&& a, const B&)
    {
    std::cout << "op<<";
    return a;
    }

    int main()
    {
    B b;
    A() << b; // line 17: OK
    A() << b << b; // line 18: error
    }

    14:33:51 Paul Bibbings@JIJOU
    /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    $i686-pc-cygwin-gcc-4.5.0 -std=c++0x -c ret_by_ref.cpp
    ret_by_ref.cpp: In function ¡®int main()¡¯:
    ret_by_ref.cpp:18:16: error: cannot bind ¡®A¡¯ lvalue to ¡®A&&¡¯
    ret_by_ref.cpp:8:4: error: initializing argument 1 of ¡®A&
    operator<<(A&&, const B&)¡¯

    <snip>

    >
    > But if implement it like this:
    >
    > A&& operator<<( A&& a, const B& b )
    > {
    > return a << "B";
    > }


    What compiler are you using? I would expect this not to compile since,
    within the body of the function, a behaves as an lvalue and hence in the
    return should not bind on A&&. The following might work, but then you
    have the move semantics that your referred to earlier:

    A&& operator<<(A&& a, const B& b) // untested
    {
    a << "B"; // #1
    return std::move(a);
    }

    <snip />

    Regards

    Paul Bibbings
    Paul Bibbings, Apr 28, 2010
    #18
  19. DeMarcus <> writes:

    >> So, you would have to adjust and not return a reference, say:
    >>
    >> A&& operator<<(A&&, const B&)
    >>
    >> But then, your chaining wouldn't work in the same way, and
    >>
    >> A() << aB << anotherB << yetAnotherB;
    >>
    >> would involve a succession of distinct temporary instances of A.
    >>

    >
    > I solved it! I think. How about this in A.hpp?
    >
    > template<typename T>
    > inline A&& operator<<( A&& a, const T& t )
    > {
    > std::cout << "Delegating..." << std::endl;
    > return operator<<( a, t );
    > }


    Clearly you are avoiding infinite recursion here in the call to return
    operator<<( a, t ). How are you achieving that? What /other/
    definition of op<< are you using? The one defined in the class A? But
    that returns A&, doesn't it? And then that shouldn't bind to the return
    of A&& here.

    I might be getting a little lost here, so can I ask... Does your
    compiler compile this?:

    A&& operator<<(A&& a, const B&)
    {
    return a;
    }

    (Note: it *shouldn't*)

    Regards

    Paul Bibbings
    Paul Bibbings, Apr 28, 2010
    #19
  20. DeMarcus

    DeMarcus Guest

    Paul Bibbings wrote:
    > DeMarcus <> writes:
    >
    >>> If you are going to allow use of your `stream' utilizing temporaries
    >>> formed by A(), then you are essentially breaking the `model'. If you
    >>> implement it as:
    >>>
    >>> A& operator<<(A&&, const B&)
    >>>
    >>> then you're going to be running into a few problems. Firstly, with this
    >>> you are returning a reference to a temporary that has no existence after
    >>> the call.

    >> Yes, but as far as I remember, the temporary should live the whole
    >> full-expression, i.e. the whole chaining.

    >
    > I would need to look into the detail as I'm a little hazy on whether
    > that would be the case or not. However, there are other issues here.
    > One is that chaining is not actually even possible with the above
    > signature, since the return of an lvalue ref prevents the second
    > invocation in the chain since the argument is not now an rvalue any
    > more.
    >
    > 14:33:46 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution $cat
    > ret_by_ref.cpp
    > // file: ret_by_ref.cpp
    >
    > #include <iostream>
    >
    > class A { };
    > class B { };
    >
    > A& operator<<(A&& a, const B&)
    > {
    > std::cout << "op<<";
    > return a;
    > }
    >
    > int main()
    > {
    > B b;
    > A() << b; // line 17: OK
    > A() << b << b; // line 18: error
    > }
    >
    > 14:33:51 Paul Bibbings@JIJOU
    > /cygdrive/d/CPPProjects/CLCPP/consistent_resolution
    > $i686-pc-cygwin-gcc-4.5.0 -std=c++0x -c ret_by_ref.cpp
    > ret_by_ref.cpp: In function ¡®int main()¡¯:
    > ret_by_ref.cpp:18:16: error: cannot bind ¡®A¡¯ lvalue to ¡®A&&¡¯
    > ret_by_ref.cpp:8:4: error: initializing argument 1 of ¡®A&
    > operator<<(A&&, const B&)¡¯
    >
    > <snip>
    >
    >> But if implement it like this:
    >>
    >> A&& operator<<( A&& a, const B& b )
    >> {
    >> return a << "B";
    >> }

    >
    > What compiler are you using? I would expect this not to compile since,
    > within the body of the function, a behaves as an lvalue and hence in the
    > return should not bind on A&&. The following might work, but then you
    > have the move semantics that your referred to earlier:
    >
    > A&& operator<<(A&& a, const B& b) // untested
    > {
    > a << "B"; // #1
    > return std::move(a);
    > }
    >


    It seems to compile fine without std::move(a) in gcc 4.4.1
    I went into an endless loop when doing a << "B" so I changed it for
    a.set(4711) where set() just set some variable in a. But there were no
    problems compiling either of them. I agree it's a bit tricky to
    understand fully what to expect from those && variables.
    DeMarcus, Apr 28, 2010
    #20
    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. Andrew FPGA
    Replies:
    0
    Views:
    960
    Andrew FPGA
    Sep 26, 2005
  2. Replies:
    8
    Views:
    6,839
    Michele Simionato
    Jun 27, 2006
  3. TimeHorse
    Replies:
    0
    Views:
    290
    TimeHorse
    Oct 27, 2007
  4. Clifford Heath
    Replies:
    3
    Views:
    105
    Clifford Heath
    Mar 12, 2008
  5. Robert Oschler
    Replies:
    1
    Views:
    92
    Grant Wagner
    Aug 24, 2005
Loading...

Share This Page