www.digitalmars.com         C & C++   DMDScript  

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

reply Neal Becker <ndbecker2 gmail.com> writes:
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
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
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
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
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
parent reply Neal Becker <ndbecker2 gmail.com> writes:
Sean Kelly wrote:

 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.
Ouch, I had oversimplified the problem. The above does compile. OK, here 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>*,
std::vector<std::complex<double>, std::allocator<std::complex<double> > >
, __gnu_cxx::__normal_iterator<double*, std::vector<double,
std::allocator<double> > >, <unresolved overloaded function type>)’ 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
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
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
prev sibling next sibling parent guslay <guslay gmail.com> writes:
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
prev sibling parent Sean Kelly <sean f4.ca> writes:
Neal Becker wrote:
 Sean Kelly wrote:
 
 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.
Ouch, I had oversimplified the problem. The above does compile. OK, here 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>*,
std::vector<std::complex<double>, std::allocator<std::complex<double> > >
 , __gnu_cxx::__normal_iterator<double*, std::vector<double,
std::allocator<double> > >, <unresolved overloaded function type>)’ 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