## digitalmars.D - one thing that bugs me about c++

- Neal Becker <ndbecker2 gmail.com> Dec 13 2007
- Walter Bright <newshound1 digitalmars.com> Dec 13 2007
- Sean Kelly <sean f4.ca> Dec 13 2007
- Neal Becker <ndbecker2 gmail.com> Dec 13 2007
- Walter Bright <newshound1 digitalmars.com> Dec 13 2007
- guslay <guslay gmail.com> Dec 13 2007
- Sean Kelly <sean f4.ca> Dec 13 2007

In c++, template<typename T> void F (T); template<typename T> void F (std::complex<T>); This doesn't work. I want the second overload to be the 'best' match for F (std::complex<double>) for example, but the standard doesn't agree. Never really made sense to me. What would D do?

Dec 13 2007

Neal Becker wrote:In c++, template<typename T> void F (T); template<typename T> void F (std::complex<T>); This doesn't work. I want the second overload to be the 'best' match for F (std::complex<double>) for example, but the standard doesn't agree. Never really made sense to me. What would D do?

void F(T)(T t) { ... } void F(T:cdouble)(T t) { ... } should do it.

Dec 13 2007

Neal Becker wrote:In c++, template<typename T> void F (T); template<typename T> void F (std::complex<T>); This doesn't work. I want the second overload to be the 'best' match for F (std::complex<double>) for example, but the standard doesn't agree. Never really made sense to me. What would D do?

Seems I need to brush up on my knowledge of template overload resolution, as I'd expect the second overload to be chosen for the reason you provide. Still, perhaps it isn't truly "more specialized" because in each case a T is being substituted into the one parameter? I'll give the C++ spec a gander on my way home and see if I can come up with anything more enlightening. Sean

Dec 13 2007

Sean Kelly wrote:Neal Becker wrote:

Seems I need to brush up on my knowledge of template overload resolution, as I'd expect the second overload to be chosen for the reason you provide. Still, perhaps it isn't truly "more specialized" because in each case a T is being substituted into the one parameter? I'll give the C++ spec a gander on my way home and see if I can come up with anything more enlightening.

is the _real_ problem: -------------------- #include <complex> #include <vector> using namespace std; template<typename T> T mag_sqr1 (T z) { return z * z; } template<typename T> T mag_sqr1 (complex<T> z) { return real(z)*real(z) + imag(z)*imag(z); } template<typename T> struct scalar { typedef T type; }; template<typename T> struct scalar<complex<T> > { typedef T type; }; template<typename T> inline vector<typename scalar<T>::type> mag_sqr (vector<T> const& z) { typedef typename scalar<T>::type out_t; vector<out_t> out (z.size()); std::transform (z.begin(), z.end(), out.begin(), mag_sqr1<T>); return out; } int main () { vector<complex<double> > v; mag_sqr (v); } ------------------ test1.cc:29: instantiated from here test1.cc:23: error: no matching function for call to â€˜transform(__gnu_cxx::__normal_iterator<const std::complex<double>*, std::vector<std::complex<double>, std::allocator<std::complex<double> > >, __gnu_cxx::__normal_iterator<const std::complex<double>*,

, __gnu_cxx::__normal_iterator<double*, std::vector<double,

But if we change the mag_sqr1 from overloaded functions to functors, this compiles fine. (and change the call to: std::transform (z.begin(), z.end(), out.begin(), mag_sqr1<T>()) )

Dec 13 2007

Neal Becker wrote:template<typename T> inline vector<typename scalar<T>::type> mag_sqr (vector<T> const& z) { typedef typename scalar<T>::type out_t; vector<out_t> out (z.size()); std::transform (z.begin(), z.end(), out.begin(), mag_sqr1<T>); return out; }

That just makes my eyeballs hurt.

Dec 13 2007

Neal Becker Wrote:-------------------- #include <complex> #include <vector> using namespace std; template<typename T> T mag_sqr1 (T z) { return z * z; } template<typename T> T mag_sqr1 (complex<T> z) { return real(z)*real(z) + imag(z)*imag(z); } template<typename T> struct scalar { typedef T type; }; template<typename T> struct scalar<complex<T> > { typedef T type; }; template<typename T> inline vector<typename scalar<T>::type> mag_sqr (vector<T> const& z) { typedef typename scalar<T>::type out_t; vector<out_t> out (z.size()); std::transform (z.begin(), z.end(), out.begin(), mag_sqr1<T>); return out; } int main () { vector<complex<double> > v; mag_sqr (v); }

The instantiation capability within std::transform appears to be the limitation. Who knows why. If you do it in two steps, by first defining a function pointer, it works fine for complex and double. out_t (*ptrF)(T) = &mag_sqr1; std::transform (z.begin(), z.end(), out.begin(), ptrF ); I will leave the implementation in D to someone else, but I bet it would look better.

Dec 13 2007

Neal Becker wrote:Sean Kelly wrote:Neal Becker wrote:

resolution, as I'd expect the second overload to be chosen for the reason you provide. Still, perhaps it isn't truly "more specialized" because in each case a T is being substituted into the one parameter? I'll give the C++ spec a gander on my way home and see if I can come up with anything more enlightening.

is the _real_ problem: -------------------- #include <complex> #include <vector> using namespace std; template<typename T> T mag_sqr1 (T z) { return z * z; } template<typename T> T mag_sqr1 (complex<T> z) { return real(z)*real(z) + imag(z)*imag(z); } template<typename T> struct scalar { typedef T type; }; template<typename T> struct scalar<complex<T> > { typedef T type; }; template<typename T> inline vector<typename scalar<T>::type> mag_sqr (vector<T> const& z) { typedef typename scalar<T>::type out_t; vector<out_t> out (z.size()); std::transform (z.begin(), z.end(), out.begin(), mag_sqr1<T>); return out; } int main () { vector<complex<double> > v; mag_sqr (v); } ------------------ test1.cc:29: instantiated from here test1.cc:23: error: no matching function for call to â€˜transform(__gnu_cxx::__normal_iterator<const std::complex<double>*, std::vector<std::complex<double>, std::allocator<std::complex<double> > >, __gnu_cxx::__normal_iterator<const std::complex<double>*,

, __gnu_cxx::__normal_iterator<double*, std::vector<double,

But if we change the mag_sqr1 from overloaded functions to functors, this compiles fine. (and change the call to: std::transform (z.begin(), z.end(), out.begin(), mag_sqr1<T>()) )

The error message in VC 8 is a bit more understandable: cannot deduce template argument as function argument is ambiguous If I explicitly specify the in and out iterator types and have it just deduce the function type, I also see this as a supplementary message: could not deduce template argument for 'overloaded function type' from 'overloaded function type' I'd have to spend some time reasoning this one out, but it looks like SFINAE isn't even coming into play in this case. Sean

Dec 13 2007