简体   繁体   中英

resolve address from overloaded function std::real<float>

std::vector<std::complex<float> > c;
std::vector<float> d;
std::transform(c.begin(), c.end(), d.begin(), std::real<float>);

Why couldn't the compiler resolve the address from the overloaded function real<float> ?

Which overloaded functions does the compiler mean?

Your library implementation has provided additional overloads for std::real<float> .

Why the overloads?

26.4.9 Additional overloads [cmplx.over]

  • 1 The following function templates shall have additional overloads:

     arg norm conj proj imag real 
  • 2 The additional overloads shall be sufficient to ensure:
    1. If the argument has type long double , then it is effectively cast to complex<long double> .
    2. Otherwise, if the argument has type double or an integer type, then it is effectively cast to complex<double> .
    3. Otherwise, if the argument has type float , then it is effectively cast to complex<float> .

[...]

Solutions to problem:

You could just use a range based for ...

for (auto v : c) d.push_back(real(v));

... or pack the call to real into a functor or another function ...

struct my_caller {
    template <typename T> T operator() (std::complex<T> const &c) {
        return real(c);
    }
};

... or use the member function ...

std::transform(c.begin(), c.end(), d.begin(), [](std::complex<T> const &c) { 
    return c.real();
});

IMPORTANT:

Note that you have to have enough space in the target when using transform :

std::vector<float> d (c.size());

or use a back inserter:

std::transform(c.begin(), c.end(), back_inserter(d), ...);

Otherwise you are iterating over undefined memory, yielding undefined behaviour.

§26.4.9 states that (amongst others), real shall have additional overloads, for arguments of type float, double and long double. It seems your libraray implementation made a template for these overloads, maybe like

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

In addition to the solutions phresnel priovided, you could explicitly tell the compiler which kind of function pointer you mean:

std::transform(c.begin(), c.end(), d.begin(), (float(*)(std::complex<float> const&))std::real<float>);

The compiler then looks for a std::real that can be converted into a function pointer of the given type and will find the correct one.

I tell you this only for completeness - I consider this explicit cast ugly and would prefer the ranged based for or transform with a lambda.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM