Help Required: Operator overloaded function template and Friend

Discussion in 'C++' started by CoolPint, Feb 12, 2005.

  1. CoolPint

    CoolPint Guest

    After upgrading to gcc 3.4.2 from gcc 3.2.3, I got compiler errors
    that I could not figure out. After reading other postings, I learned
    that my coding was not compliant to the standard in the first place
    and I did fix many of them, especially with the proper use of the
    keyword "typename".

    But I have one problem I have no idea how to fix. I created below a
    simpler coding which demonstrates my problem:

    The coding below used to compile and run fine under gcc 3.2.3, but
    under 3.4.2, it doesn't compile with the error message "no match for
    'operator==' in 'a==b'

    What I read is that 3.4.2 is more compliant to the standard so I
    believe it's my coding which is wrong, but I cannot figure out what is
    wrong.

    My guessing is that for some reason, the compiler doesn't "use" the
    operator function template to instantiate a function to serve 'a ==
    b'.

    If I modify the friend declaration to include the definition of the
    function inline, then it works as I guessed since each instantiation
    of the class template will instantiate a corresponding global friend
    function.

    I will be very grateful if someone can kindly explain what the problem
    is and how to fix the problem without making the function template
    into an inlined global friend function I described above.

    Thank you very much in advance.

    template <typename T>
    class Obj {
    public:
    class Sub;
    };

    template <typename T>
    bool operator==(const typename Obj<T>::Sub & a, const typename
    Obj<T>::Sub & b)
    { return a.n == b.n; }

    template <typename T>
    class Obj<T>::Sub {
    friend bool operator==<T>(const Obj<T>::Sub &, const Obj<T>::Sub &);
    public:
    Sub(int i):n(i) { }
    private:
    int n;
    };

    #include <iostream>
    int main()
    {
    Obj<int>::Sub a(10),b(10);
    if ( a == b )
    std::cout << "OK" ;
    }
     
    CoolPint, Feb 12, 2005
    #1
    1. Advertising

  2. "CoolPint" <> wrote...
    > [...]
    > template <typename T>
    > bool operator==(const typename Obj<T>::Sub & a, const typename
    > Obj<T>::Sub & b)
    > { return a.n == b.n; }


    I think you've run into one of those "non-deducible contexts". The T is
    too deeply entrenched into the 'a' and 'b' arguments here for the compiler
    to figure out from real arguments (operands) you give it.

    > [..]
    > #include <iostream>
    > int main()
    > {
    > Obj<int>::Sub a(10),b(10);
    > if ( a == b )
    > std::cout << "OK" ;
    > }


    There are probably several ways to fix it and one would be to make your
    operator== a member:

    template <typename T>
    class Obj<T>::Sub {
    public:
    Sub(int i):n(i) { }
    bool operator==(const Obj<T>::Sub &b) const
    {
    return n == b.n;
    }
    private:
    int n;
    };

    Another way is to call the operator function using the functional notation
    with the template argument explicit:

    ...
    if (operator==<int>(a,b))
    ...

    V
     
    Victor Bazarov, Feb 12, 2005
    #2
    1. Advertising

  3. CoolPint

    CoolPint Guest

    Thank you for your help. I did think about making it a member
    function, but I was hoping to take advantage of implicit conversions.
    In fact, what I didn't show in my original posting was another problem
    where I couldn't get the implicit conversion work. It's more likely
    below where there are two nested
    classes and there is an implicit conversion from Sub2 to Sub1, but not
    vice versa. And I thought by making it a global function template, I
    could take advantage of the implicit conversion as well, but it
    doesn't work on 3.4.2 either.

    template <typename T>
    class Obj {
    public:
    class Sub1;
    class Sub2;
    };

    Thank you for your tip on using the functional notation, and probably
    I will fix my problem that way until I find a better solution, but it
    does seem to defeat the purpose of using operator overloading in the
    first place.

    I hope to get more insight to the problem by asking following
    questions if you don't mind. I apologise in advance if this is not the
    right group for this kind of questions.

    1. It used to work with gcc 3.2.3 but not with 3.4.2 anymore. What is
    the correct behaviour according to the standard? What is the rule
    governing "deducible contexts" that I should study? I also wonder what
    other compilers do with this situation since I have only gcc.

    2. If it's correct not to be able to deduce T in this case according
    to the standard, then any function template which accepts a nested
    type of a class template whose type parameter needs to be deduced from
    the funtion call arguments would never work, would it? Am I
    understanding correctly?

    Can some experts kindly provide answers to my questions above? Thank
    you very much in advance.

    > I think you've run into one of those "non-deducible contexts". The T is
    > too deeply entrenched into the 'a' and 'b' arguments here for the compiler
    > to figure out from real arguments (operands) you give it.
    >
    > > [..]
    > > #include <iostream>
    > > int main()
    > > {
    > > Obj<int>::Sub a(10),b(10);
    > > if ( a == b )
    > > std::cout << "OK" ;
    > > }

    >
    > There are probably several ways to fix it and one would be to make your
    > operator== a member:
    >
    > template <typename T>
    > class Obj<T>::Sub {
    > public:
    > Sub(int i):n(i) { }
    > bool operator==(const Obj<T>::Sub &b) const
    > {
    > return n == b.n;
    > }
    > private:
    > int n;
    > };
    >
    > Another way is to call the operator function using the functional notation
    > with the template argument explicit:
    >
    > ...
    > if (operator==<int>(a,b))
    > ...
    >
    > V
     
    CoolPint, Feb 13, 2005
    #3
  4. "CoolPint" <> wrote...
    > [...]
    > I hope to get more insight to the problem by asking following
    > questions if you don't mind. I apologise in advance if this is not the
    > right group for this kind of questions.


    It's the right newsgroup.

    > 1. It used to work with gcc 3.2.3 but not with 3.4.2 anymore. What is
    > the correct behaviour according to the standard?


    AFAIK, the inability to deduce T is the correct behaviour. What may have
    happened is that g++ provided deduction in some cases (where it didn't have
    to) and in other, similar, cases it could not deduce arguments or did it
    incorrectly. That would certainly be a bug and to fix it they decided to
    follow the Standard requirements precisely.

    To know more about the differences between 3.2.3 and 3.4.2, please visit
    their web site or post to gnu.g++.help.

    > What is the rule
    > governing "deducible contexts" that I should study?


    The rules are defined in the C++ Standard document. It's not a very good
    studying tool though. You should probably get a copy of "C++ Templates"
    by Vandevoorde and Josuttis.

    > I also wonder what
    > other compilers do with this situation since I have only gcc.


    Comeau refuses to compile stating the same reason, essentially. I leave
    it to others to test more compilers.

    > 2. If it's correct not to be able to deduce T in this case according
    > to the standard, then any function template which accepts a nested
    > type of a class template whose type parameter needs to be deduced from
    > the funtion call arguments would never work, would it? Am I
    > understanding correctly?


    Yes, AFAICT. The reason is that the "nested" type is _dependent_ on
    the template argument.

    > Can some experts kindly provide answers to my questions above?


    I am sure they will, in addition to my feeble attempt.

    > Thank
    > you very much in advance.


    And I'd like to ask for a favour. Please don't top-post next time.
    Thanks!

    >
    >> I think you've run into one of those "non-deducible contexts". The T is
    >> too deeply entrenched into the 'a' and 'b' arguments here for the
    >> compiler
    >> to figure out from real arguments (operands) you give it.
    >>
    >> > [..]
    >> > #include <iostream>
    >> > int main()
    >> > {
    >> > Obj<int>::Sub a(10),b(10);
    >> > if ( a == b )
    >> > std::cout << "OK" ;
    >> > }

    >>
    >> There are probably several ways to fix it and one would be to make your
    >> operator== a member:
    >>
    >> template <typename T>
    >> class Obj<T>::Sub {
    >> public:
    >> Sub(int i):n(i) { }
    >> bool operator==(const Obj<T>::Sub &b) const
    >> {
    >> return n == b.n;
    >> }
    >> private:
    >> int n;
    >> };
    >>
    >> Another way is to call the operator function using the functional
    >> notation
    >> with the template argument explicit:
    >>
    >> ...
    >> if (operator==<int>(a,b))
    >> ...


    V
     
    Victor Bazarov, Feb 13, 2005
    #4
    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. Nitin Bhardwaj
    Replies:
    8
    Views:
    890
    Andrey Tarasevich
    Jul 14, 2003
  2. TJ
    Replies:
    3
    Views:
    382
    David Harmon
    Apr 26, 2004
  3. Replies:
    4
    Views:
    484
  4. aravindap
    Replies:
    2
    Views:
    371
    aravindap
    Oct 24, 2008
  5. A L
    Replies:
    1
    Views:
    511
    Alf P. Steinbach /Usenet
    Aug 25, 2010
Loading...

Share This Page