<complex> : no match for 'operator*' // conversion operator double()

Discussion in 'C++' started by Arvid Requate, Jun 23, 2006.

  1. Hello,

    I'd like to understand why the following code does not compile. It
    looks like a strangeness in connection with overload resolution for the
    <complex> header:
    The conversion operator double() of class B is called for the member
    complex::eek:perator*=(double) as expected, but not for operator*(complex,
    double).

    The effect is, that the template matching (or overload resolution)
    fails. Error message:
    complex_double_conversion.cpp: In function 'int main()':
    complex_double_conversion.cpp:19: error: no match for 'operator*' in 'z
    * x'

    Tested with g++ 4.0.2 20050901 (prerelease) on (SUSE Linux) and others.
    Do <you> know a reason/remedy for this behaviour? Thanks in advance.

    //------------------------complex_double_conversion.cpp-------------------------
    #include<complex>

    class B {
    double v;
    public:
    operator double() const { return v; } // conversion operator
    B(double _v) : v(_v) {}
    };

    int main() {
    std::complex<double> z(0,1);
    B x(0.5);

    // next line works due to complex<_Tp>&
    complex<_Tp>::eek:perator*=(const _Tp&)
    // the conversion operator of class B is used
    z*=x;

    // the next line does not compile
    std::complex<double> y( z*x );

    // only with cast: z*((double) x)
    //
    // although in <complex> there is
    // template<typename _Tp>
    // inline complex<_Tp> operator*(const complex<_Tp>& __x, const
    _Tp& __y)
    // { return complex<_Tp> (__x) *= __y; }
    //
    return 0;
    }
    //-----------------------------------------------------------------------------------------
     
    Arvid Requate, Jun 23, 2006
    #1
    1. Advertising

  2. Arvid Requate

    Tom Widmer Guest

    Re: <complex> : no match for 'operator*' // conversion operatordouble()

    Arvid Requate wrote:
    > Hello,
    >
    > I'd like to understand why the following code does not compile. It
    > looks like a strangeness in connection with overload resolution for the
    > <complex> header:
    > The conversion operator double() of class B is called for the member
    > complex::eek:perator*=(double) as expected, but not for operator*(complex,
    > double).
    >
    > The effect is, that the template matching (or overload resolution)
    > fails. Error message:
    > complex_double_conversion.cpp: In function 'int main()':
    > complex_double_conversion.cpp:19: error: no match for 'operator*' in 'z
    > * x'
    >
    > Tested with g++ 4.0.2 20050901 (prerelease) on (SUSE Linux) and others.
    > Do <you> know a reason/remedy for this behaviour? Thanks in advance.


    The operator* function you want to call is a non-member as follows:
    template<class T>
    complex<T> operator*(const complex<T>& lhs, const T& rhs);

    Template argument deduction fails because it requires that the arguments
    are exact matches for the deduced parameter types (with a few
    exceptions), but B is not similar enough to double const& (user defined
    conversions aren't considered).

    The easiest fix is to write a suitable function (in the same namespace
    as B so that it is found by ADL), something like:

    complex<double> operator*(const complex<double>& lhs, const B& rhs)
    {
    return lhs * static_cast<double>(rhs);
    }

    Tom

    >
    > //------------------------complex_double_conversion.cpp-------------------------
    > #include<complex>
    >
    > class B {
    > double v;
    > public:
    > operator double() const { return v; } // conversion operator
    > B(double _v) : v(_v) {}
    > };
    >
    > int main() {
    > std::complex<double> z(0,1);
    > B x(0.5);
    >
    > // next line works due to complex<_Tp>&
    > complex<_Tp>::eek:perator*=(const _Tp&)
    > // the conversion operator of class B is used
    > z*=x;
    >
    > // the next line does not compile
    > std::complex<double> y( z*x );
    >
    > // only with cast: z*((double) x)
    > //
    > // although in <complex> there is
    > // template<typename _Tp>
    > // inline complex<_Tp> operator*(const complex<_Tp>& __x, const
    > _Tp& __y)
    > // { return complex<_Tp> (__x) *= __y; }
    > //
    > return 0;
    > }
    > //-----------------------------------------------------------------------------------------
    >
     
    Tom Widmer, Jun 23, 2006
    #2
    1. Advertising

  3. Re: <complex> : no match for 'operator*' // conversion operatordouble()

    * Arvid Requate:
    >
    > I'd like to understand why the following code does not compile.

    [snip]

    > //------------------------complex_double_conversion.cpp-------------------------
    > #include<complex>
    >
    > class B {
    > double v;
    > public:
    > operator double() const { return v; } // conversion operator
    > B(double _v) : v(_v) {}
    > };
    >
    > int main() {
    > std::complex<double> z(0,1);
    > B x(0.5);
    >
    > // next line works due to complex<_Tp>&
    > complex<_Tp>::eek:perator*=(const _Tp&)
    > // the conversion operator of class B is used
    > z*=x;
    >
    > // the next line does not compile
    > std::complex<double> y( z*x );
    >
    > // only with cast: z*((double) x)
    > //
    > // although in <complex> there is
    > // template<typename _Tp>
    > // inline complex<_Tp> operator*(const complex<_Tp>& __x, const
    > _Tp& __y)
    > // { return complex<_Tp> (__x) *= __y; }
    > //
    > return 0;
    > }
    > //-----------------------------------------------------------------------------------------


    Template parameter matching does not consider user-defined conversions:
    in general types must match exactly (sort of, there's a bit of looseness
    in cv-qualification and reference types and so on).

    Consider:

    template< typename T >
    struct Complex { Complex( T = 0, T = 0 ) {} };

    template< typename T >
    Complex<T> operator*( Complex<T> const&, Complex<T> const& )
    { return Complex<T>(); }

    class B
    {
    double v;
    public:
    B( double _v ) : v( _v ) {}
    operator Complex<double> () const { return v; }
    };

    int main()
    {
    Complex<double> z(0,1);
    B x(0.5);

    // The next line does not compile, not exact match:
    z*x;
    }

    However, adding

    template< typename T >
    Complex<T> operator*( Complex<T> const& a, B const& b )
    { return a*Complex<T>(b); }

    provides an exact match and the code compiles.

    A bit more general, adding instead

    template< template<class> class C, typename T >
    C<T> operator*( C<T> const& a, B const& b )
    { return a*C<T>(b); }

    also provides an exact match and the code compiles.

    I tried this fix with your original code and it compiles with MSVC 7.1.
    However, you'll probably also have to support the opposite argument
    order, and other operators such as '+'.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Jun 23, 2006
    #3
    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. Sydex
    Replies:
    12
    Views:
    6,528
    Victor Bazarov
    Feb 17, 2005
  2. J.M.
    Replies:
    3
    Views:
    638
    Sarath
    Mar 6, 2007
  3. J.M.
    Replies:
    5
    Views:
    788
  4. Replies:
    1
    Views:
    450
    Robert Bauck Hamar
    Jul 12, 2007
  5. Replies:
    5
    Views:
    436
    James Kanze
    Jun 27, 2008
Loading...

Share This Page