std::real() is broken when using -std=c++0x mode

Mark Tall mtall.gcc@gmail.com
Wed Nov 16 12:35:00 GMT 2011


With -std=c++0x mode, std::real() from <complex> appears to be broken.

More specifically, with -std=c++0x enabled, std::real() is confused
with a user version of real(), which is in a separate namespace.

The output of the program listed below should be:

A.val = (123,456)
B.val = 123

When using -std=c++0x, the following error occurs during compilation:

real_bug.cpp: In function ‘int main(int, char**)’:
real_bug.cpp:93: error: no match for ‘operator=’ in ‘B = std::real
[with _Tp = mylib::Mat<std::complex<double> >](A)’
real_bug.cpp:52: note: candidates are: mylib::Mat<double>&
mylib::Mat<double>::operator=(const mylib::Mat<double>&)

Note that the compiler wants to call std::real(), while it should be
calling mylib::real() instead.

I'm using gcc 4.4.5 from Scientific Linux 6.1 (a clone of Red Hat
Enterprise Linux 6.1) on an x86_64 machine.  I've also tried clang++
2.8, and the code compiles fine.

A colleague has also encountered a similar bug (or perhaps the same
bug) in gcc 4.6.

Bug filed as:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51158


real_bug.cpp:
#include <iostream>
#include <complex>

namespace mylib
  {
  template<typename T, typename derived>
  struct Base
    {
    const derived& get_ref() const
    { return static_cast<const derived&>(*this); }
    };


  template<typename T, typename Obj>
  class delayed_real;

  template<typename T>
  class Mat;


  template<typename T>
  struct strip_cx
  { typedef T result; };

  template<typename T>
  struct strip_cx< std::complex<T> >
  { typedef T result; };


  template<typename T>
  const T&
  get_real(const T& X) { return X; }

  template<typename T>
  const T
  get_real(const std::complex<T>& X) { return X.real(); }


  template<typename out_T, typename Obj>
  struct
  delayed_real
    {
    const Obj& X;

    explicit delayed_real(const Obj& in_X) : X(in_X) {}
    };


  template<typename T>
  struct
  Mat : public Base< T, Mat<T> >
    {
    T val;

    Mat() : val() {}

    template<typename Obj>
    void
    operator=(const delayed_real<T, Obj>& tmp)
    { val = get_real(tmp.X.val); }

    };


  template<typename T, typename Obj>
  const delayed_real< typename strip_cx<T>::result, Obj>
  real(const Base< std::complex<T>, Obj>& X)
    {
    return
    delayed_real< typename strip_cx<T>::result, Obj >
    (X.get_ref());
    }

  }



using namespace std;
using namespace mylib;


int
main(int argc, char** argv)
  {
  typedef std::complex<double> cx_double;

  Mat<cx_double> A;
  A.val = cx_double(123,456);

  cout << "A.val = " << A.val << endl;

  Mat<double> B;
  B = real(A);  // broken when using -std=c++0x

  // explicit namespace specification required for -std=c++0x
  //B = mylib::real(A);

  cout << "B.val = " << B.val << endl;

  return 0;
  }



More information about the Libstdc++ mailing list