Template considered ambiguous

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • neildferguson@hotmail.com

    Template considered ambiguous

    I am using templates with a little project I am working on. My compiler (GCC)
    is finding a particular construct ambiguous. Can anyone suggest something I
    might change in the declaration of class Length so that I can use operator+ the
    way I'd like?

    //=============== =============== ===========
    // File lentest.h:

    #ifndef FDIMENS_LENGTH_ INCL
    #define FDIMENS_LENGTH_ INCL

    class EU {};
    class MT : public EU {};
    class KM : public EU {};
    class FT : public EU {};
    class YD : public EU {};

    template <class U>
    class Length
    {
    public :
    Length<U>()
    {
    }
    Length<U>(doubl e inUnits)
    {
    }
    template <class O>
    Length<U>(const Length<O&other)
    {
    }
    template <class O>
    Length<U&operat or=(const Length<O&other)
    {
    return *this;
    }
    template <class O>
    friend Length<Uoperato r+(const Length<U&lhs, const Length<O>
    &rhs)
    {
    Length<Uret;
    return ret;
    }
    template <class O>
    friend Length<Uoperato r+(double lhs, const Length<O&rhs)
    {
    Length<Uret;
    return ret;
    }
    operator double() const { return m_lenUnits; }
    private :
    static double m_m2u;
    static double m_u2m;
    };
    template<double Length<MT>::m_m 2u = 1.0;
    template<double Length<MT>::m_u 2m = 1.0;

    template<double Length<KM>::m_m 2u = 0.001;
    template<double Length<KM>::m_u 2m = 1000.0;

    template<double Length<FT>::m_m 2u = 3.28083986538;
    template<double Length<FT>::m_u 2m = 0.3048;

    template<double Length<YD>::m_m 2u = (3.28083986538/3.0);
    template<double Length<YD>::m_u 2m = (0.3048*3.0);
    #endif // FDIMENS_LENGTH_ INCL

    //=============== =============== ===============
    // File lentest.cpp
    // lentest.cpp : Defines the entry point for the console application.
    //
    #include <stdio.h>

    #include "lentest.h"

    int main()
    {
    Length<FTft1(34 .0);
    Length<FTft2 = (Length<FT>)27. 0 + ft1;
    #if 0 // this line is ambiguous
    Length<FTft3 = 27.0 + ft2;
    #endif
    return 0;
    }


    ----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
    http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
    ----= East and West-Coast Server Farms - Total Privacy via Encryption =----
  • Victor Bazarov

    #2
    Re: Template considered ambiguous

    neildferguson@h otmail.com wrote:
    I am using templates with a little project I am working on. My
    compiler (GCC)
    is finding a particular construct ambiguous. Can anyone suggest
    something I
    might change in the declaration of class Length so that I can use
    operator+ the way I'd like?
    Change compilers? Both Comeau online and VC++ 2005 are fine with
    your code...
    [..]
    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask


    Comment

    • neildferguson@hotmail.com

      #3
      Re: Template considered ambiguous

      On Tue, 20 Nov 2007 23:25:37 -0500, "Victor Bazarov" <v.Abazarov@com Acast.net>
      wrote:
      >neildferguson@ hotmail.com wrote:
      >I am using templates with a little project I am working on. My
      >compiler (GCC)
      >is finding a particular construct ambiguous. Can anyone suggest
      >something I
      >might change in the declaration of class Length so that I can use
      >operator+ the way I'd like?
      >
      >Change compilers? Both Comeau online and VC++ 2005 are fine with
      >your code...
      >
      >[..]
      >
      >V
      You mean I did it correctly? That's the last thing I would have guessed.

      Unfortunately my MSDN set is rather old - VisualC++ expires from internal
      injuries. I tried upgrading (Cygwin) gcc to version 3.4.4, without any better
      luck. Time to rethink.

      And thank you for the referral to Comeau online.

      Neil

      BTW: The error is:

      lentest.cpp:12: error: ambiguous overload for 'operator+' in '2.7e+1 + ft2'
      lentest.cpp:12: note: candidates are: operator+(doubl e, double) <built-in>
      lentest.h:31: note: Length<Uoperato r+(const Length<U>&, const Length<O>&)
      [with O = FT, U = MT]
      lentest.h:37: note: Length<Uoperato r+(double, const Length<O>&) [with O = FT,
      U = MT]
      lentest.h:31: note: Length<Uoperato r+(const Length<U>&, const Length<O>&)
      [with O = FT, U = KM]
      lentest.h:37: note: Length<Uoperato r+(double, const Length<O>&) [with O = FT,
      U = KM]
      lentest.h:31: note: Length<Uoperato r+(const Length<U>&, const Length<O>&)
      [with O = FT, U = FT]
      lentest.h:37: note: Length<Uoperato r+(double, const Length<O>&) [with O = FT,
      U = FT]
      lentest.h:31: note: Length<Uoperato r+(const Length<U>&, const Length<O>&)
      [with O = FT, U = YD]
      lentest.h:37: note: Length<Uoperato r+(double, const Length<O>&) [with O = FT,
      U = YD]

      ----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
      http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
      ----= East and West-Coast Server Farms - Total Privacy via Encryption =----

      Comment

      • Kai-Uwe Bux

        #4
        Re: Template considered ambiguous

        Victor Bazarov wrote:
        neildferguson@h otmail.com wrote:
        >I am using templates with a little project I am working on. My
        >compiler (GCC)
        >is finding a particular construct ambiguous. Can anyone suggest
        >something I
        >might change in the declaration of class Length so that I can use
        >operator+ the way I'd like?
        >
        Change compilers? Both Comeau online and VC++ 2005 are fine with
        your code...
        Hm, maybe they are both wrong.


        Consider

        template <class Uclass Length {
        public :
        // ...
        template <class O>
        friend Length<Uoperato r+(double lhs, const Length<O&rhs)
        { ... }
        // ...
        };

        Then, in main we find:

        27.0 + ft2

        where ft2 is of type Length<FT>. How is the compiler supposed to deduce
        whether the result will be of type Length<FTor Length<YDor ...? Each
        Length<Twants to add an overload that matches the arguments perfectly.

        Am I missing some rule on overload resolution that would disambiguate?


        Best

        Kai-Uwe Bux

        Comment

        • Ian Collins

          #5
          Re: Template considered ambiguous

          Kai-Uwe Bux wrote:
          Victor Bazarov wrote:
          >Change compilers? Both Comeau online and VC++ 2005 are fine with
          >your code...
          >
          Hm, maybe they are both wrong.
          >
          Consider
          >
          template <class Uclass Length {
          public :
          // ...
          template <class O>
          friend Length<Uoperato r+(double lhs, const Length<O&rhs)
          { ... }
          // ...
          };
          >
          Then, in main we find:
          >
          27.0 + ft2
          >
          where ft2 is of type Length<FT>. How is the compiler supposed to deduce
          whether the result will be of type Length<FTor Length<YDor ...? Each
          Length<Twants to add an overload that matches the arguments perfectly.
          >
          Am I missing some rule on overload resolution that would disambiguate?
          >
          I don't think it can, hence the error form gcc, which lists all the
          possibilities!

          Sun CC gives what on the surface appears an unhelpful error:

          Overloading ambiguity between "operator+<FT>( double, const Length<FT>&)"
          and "operator+<FT>( double, const Length<FT>&)"

          Which is makes sense given the ambiguity is with the return type.

          --
          Ian Collins.

          Comment

          • James Kanze

            #6
            Re: Template considered ambiguous

            On Nov 21, 7:05 am, Kai-Uwe Bux <jkherci...@gmx .netwrote:
            Victor Bazarov wrote:
            neildfergu...@h otmail.com wrote:
            I am using templates with a little project I am working on. My
            compiler (GCC)
            is finding a particular construct ambiguous. Can anyone suggest
            something I
            might change in the declaration of class Length so that I can use
            operator+ the way I'd like?
            Change compilers? Both Comeau online and VC++ 2005 are fine with
            your code...
            Hm, maybe they are both wrong.
            Or maybe g++ is still supporting some older rules of name
            injection (perhaps intentionally, to avoid breaking existing
            code.
            Consider
            template <class Uclass Length {
            public :
            // ...
            template <class O>
            friend Length<Uoperato r+(double lhs, const Length<O&rhs)
            { ... }
            // ...
            Note that according to the standard, this operator is *NOT*
            visible in global namespace; the name of friend functions is not
            injected into the enclosing namespace. That means that this
            function can only be found 1) if the code is in a member
            function, or 2) if ADL brings it into scope.
            };
            Then, in main we find:
            27.0 + ft2
            where ft2 is of type Length<FT>. How is the compiler supposed
            to deduce whether the result will be of type Length<FTor
            Length<YDor ...?
            Why does it have to deduce? Normal lookup finds none of the
            overloads. ADL finds the overload in Length<FT>, and only that
            overload.
            Each Length<Twants to add an overload that matches the
            arguments perfectly.
            Am I missing some rule on overload resolution that would
            disambiguate?
            The fact that the operator+ funnction is only visible because of
            ADL. And ADL only looks in Length<FT>.

            --
            James Kanze (GABI Software) email:james.kan ze@gmail.com
            Conseils en informatique orientée objet/
            Beratung in objektorientier ter Datenverarbeitu ng
            9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

            Comment

            • Kai-Uwe Bux

              #7
              Re: Template considered ambiguous

              James Kanze wrote:
              On Nov 21, 7:05 am, Kai-Uwe Bux <jkherci...@gmx .netwrote:
              >Victor Bazarov wrote:
              neildfergu...@h otmail.com wrote:
              >I am using templates with a little project I am working on. My
              >compiler (GCC)
              >is finding a particular construct ambiguous. Can anyone suggest
              >something I
              >might change in the declaration of class Length so that I can use
              >operator+ the way I'd like?
              >
              Change compilers? Both Comeau online and VC++ 2005 are fine with
              your code...
              >
              >Hm, maybe they are both wrong.
              >
              Or maybe g++ is still supporting some older rules of name
              injection (perhaps intentionally, to avoid breaking existing
              code.
              I doubt that it is intentional. My experience with g++ is that upgrades can
              be pretty reckless.

              >Consider
              >
              >template <class Uclass Length {
              >public :
              > // ...
              > template <class O>
              > friend Length<Uoperato r+(double lhs, const Length<O&rhs)
              > { ... }
              > // ...
              >
              Note that according to the standard, this operator is *NOT*
              visible in global namespace; the name of friend functions is not
              injected into the enclosing namespace. That means that this
              function can only be found 1) if the code is in a member
              function, or 2) if ADL brings it into scope.
              >
              >};
              >
              >Then, in main we find:
              >
              > 27.0 + ft2
              >
              >where ft2 is of type Length<FT>. How is the compiler supposed
              >to deduce whether the result will be of type Length<FTor
              >Length<YDor ...?
              >
              Why does it have to deduce? Normal lookup finds none of the
              overloads. ADL finds the overload in Length<FT>, and only that
              overload.
              Good point.

              That implies, however, that

              Length<U>::oper ator+( double, Length<Oconst & )

              will only be found through ADL when U=O because only Length<Owill be
              searched.

              In that case, the following should suffice:

              template <class Uclass Length {
              public :
              // ...
              friend Length operator+(doubl e lhs, const Length &rhs)
              { ... }
              // ...
              };


              Maybe this rewrite will placate g++.



              Best

              Kai-Uwe

              Comment

              • James Kanze

                #8
                Re: Template considered ambiguous

                On Nov 21, 1:25 pm, Kai-Uwe Bux <jkherci...@gmx .netwrote:
                James Kanze wrote:
                On Nov 21, 7:05 am, Kai-Uwe Bux <jkherci...@gmx .netwrote:
                Victor Bazarov wrote:
                neildfergu...@h otmail.com wrote:
                I am using templates with a little project I am working on. My
                compiler (GCC)
                is finding a particular construct ambiguous. Can anyone suggest
                something I
                might change in the declaration of class Length so that I can use
                operator+ the way I'd like?
                Change compilers? Both Comeau online and VC++ 2005 are fine with
                your code...
                Hm, maybe they are both wrong.
                Or maybe g++ is still supporting some older rules of name
                injection (perhaps intentionally, to avoid breaking existing
                code.
                I doubt that it is intentional. My experience with g++ is that
                upgrades can be pretty reckless.
                But usually in the opposite direction. Working code breaks,
                because it isn't 100% standards conform. (The fact that the
                code was written before the standard doesn't seem to bother the
                g++ maintainers. And to be fair, it depends on which
                one---sometimes, they do a very good job with regards to
                backwards compatibility, and other times, you get the impression
                that they went out of their way to break it.)
                Consider
                template <class Uclass Length {
                public :
                // ...
                template <class O>
                friend Length<Uoperato r+(double lhs, const Length<O&rhs)
                { ... }
                // ...
                Note that according to the standard, this operator is *NOT*
                visible in global namespace; the name of friend functions is not
                injected into the enclosing namespace. That means that this
                function can only be found 1) if the code is in a member
                function, or 2) if ADL brings it into scope.
                };
                Then, in main we find:
                >
                27.0 + ft2
                where ft2 is of type Length<FT>. How is the compiler supposed
                to deduce whether the result will be of type Length<FTor
                Length<YDor ...?
                Why does it have to deduce? Normal lookup finds none of the
                overloads. ADL finds the overload in Length<FT>, and only that
                overload.
                Good point.
                That implies, however, that
                Length<U>::oper ator+( double, Length<Oconst & )
                will only be found through ADL when U=O because only Length<O>
                will be searched.
                Pretty much, I think:-).

                Off hand, my impression was that the OP had gotten a little bit
                carried away with templated operators, to the point of possibly
                looking for trouble (ambiguous calls).

                In this case, if the compiler implements the older rules (with
                friends being injected into the surrounding namespace), the call
                can only be ambiguous, since the compiler really has to deduce
                two types, and it doesn't have the information for one of them.
                If the compiler implements the new rules (with no friend name
                injection, but with ADL finding the friend), then the only time
                the function will be found is when O and U are the same.

                Note that something like:

                template< typename O >
                friend Length operator+( Length const& lhs, Length<Oconst&
                rhs ) ;

                would work. The version of operator+ that would be used would
                always come from the type of the first operand, of course.
                In that case, the following should suffice:
                template <class Uclass Length {
                public :
                // ...
                friend Length operator+(doubl e lhs, const Length &rhs)
                { ... }
                // ...
                };
                Maybe this rewrite will placate g++.
                Probably. I use something fairly similar all the time:

                --------- Operators.hh ----------
                template< typename Owner >
                class Operators
                {
                friend Owner operator+( Owner const& lhs, Owner const& rhs )
                {
                Owner result( lhs ) ;
                result += rhs ;
                return result ;
                }
                // ...
                } ;

                ---------- SomeOtherClass. hh ---------
                class Toto : public Operators< Toto >
                {
                } ;

                Of course, Operators implements *all* of the usual operators,
                along the same lines. So that anytime I implement <op>= as a
                member function, by deriving from Operator, I get the
                corresponding binary function.

                --
                James Kanze (GABI Software) email:james.kan ze@gmail.com
                Conseils en informatique orientée objet/
                Beratung in objektorientier ter Datenverarbeitu ng
                9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

                Comment

                • Kai-Uwe Bux

                  #9
                  Re: Template considered ambiguous

                  James Kanze wrote:
                  On Nov 21, 1:25 pm, Kai-Uwe Bux <jkherci...@gmx .netwrote:
                  >James Kanze wrote:
                  On Nov 21, 7:05 am, Kai-Uwe Bux <jkherci...@gmx .netwrote:
                  >Victor Bazarov wrote:
                  neildfergu...@h otmail.com wrote:
                  >I am using templates with a little project I am working on. My
                  >compiler (GCC)
                  >is finding a particular construct ambiguous. Can anyone suggest
                  >something I
                  >might change in the declaration of class Length so that I can use
                  >operator+ the way I'd like?
                  >
                  Change compilers? Both Comeau online and VC++ 2005 are fine with
                  your code...
                  >
                  >Hm, maybe they are both wrong.
                  >
                  Or maybe g++ is still supporting some older rules of name
                  injection (perhaps intentionally, to avoid breaking existing
                  code.
                  >
                  >I doubt that it is intentional. My experience with g++ is that
                  >upgrades can be pretty reckless.
                  >
                  But usually in the opposite direction. Working code breaks,
                  because it isn't 100% standards conform.
                  I think, that _is_ intentional.

                  The reason I think the current case is not intentional is precisely that it
                  is the other way around: the compiler chokes on what appears to be correct
                  code.


                  [snip]


                  Best

                  Kai-Uwe Bux

                  Comment

                  • neildferguson@hotmail.com

                    #10
                    Re: Template considered ambiguous

                    On Wed, 21 Nov 2007 04:25:48 -0800, Kai-Uwe Bux <jkherciueh@gmx .netwrote:
                    >James Kanze wrote:
                    >
                    >On Nov 21, 7:05 am, Kai-Uwe Bux <jkherci...@gmx .netwrote:
                    >>Victor Bazarov wrote:
                    >neildfergu...@ hotmail.com wrote:
                    >>I am using templates with a little project I am working on. My
                    >>compiler (GCC)
                    >>is finding a particular construct ambiguous. Can anyone suggest
                    >>something I
                    >>might change in the declaration of class Length so that I can use
                    >>operator+ the way I'd like?
                    >>
                    >Change compilers? Both Comeau online and VC++ 2005 are fine with
                    >your code...
                    >>
                    >>Hm, maybe they are both wrong.
                    >>
                    >Or maybe g++ is still supporting some older rules of name
                    >injection (perhaps intentionally, to avoid breaking existing
                    >code.
                    >
                    >I doubt that it is intentional. My experience with g++ is that upgrades can
                    >be pretty reckless.
                    >
                    >
                    >>Consider
                    >>
                    >>template <class Uclass Length {
                    >>public :
                    >> // ...
                    >> template <class O>
                    >> friend Length<Uoperato r+(double lhs, const Length<O&rhs)
                    >> { ... }
                    >> // ...
                    >>
                    >Note that according to the standard, this operator is *NOT*
                    >visible in global namespace; the name of friend functions is not
                    >injected into the enclosing namespace. That means that this
                    >function can only be found 1) if the code is in a member
                    >function, or 2) if ADL brings it into scope.
                    >>
                    >>};
                    >>
                    >>Then, in main we find:
                    >>
                    >> 27.0 + ft2
                    >>
                    >>where ft2 is of type Length<FT>. How is the compiler supposed
                    >>to deduce whether the result will be of type Length<FTor
                    >>Length<YDor ...?
                    >>
                    >Why does it have to deduce? Normal lookup finds none of the
                    >overloads. ADL finds the overload in Length<FT>, and only that
                    >overload.
                    >
                    >Good point.
                    >
                    >That implies, however, that
                    >
                    Length<U>::oper ator+( double, Length<Oconst & )
                    >
                    >will only be found through ADL when U=O because only Length<Owill be
                    >searched.
                    >
                    >In that case, the following should suffice:
                    >
                    template <class Uclass Length {
                    public :
                    // ...
                    friend Length operator+(doubl e lhs, const Length &rhs)
                    { ... }
                    // ...
                    };
                    >
                    >
                    >Maybe this rewrite will placate g++.
                    >
                    >
                    >
                    >Best
                    >
                    >Kai-Uwe
                    It seems to have done the trick! I apparently need similar routines for int &
                    unsigned int (which handle char, unsigned char, short, unsigned short), plus
                    float.

                    Many thanks.


                    ----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
                    http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
                    ----= East and West-Coast Server Farms - Total Privacy via Encryption =----

                    Comment

                    Working...