| Thread overview | |||||||||
|---|---|---|---|---|---|---|---|---|---|
|
December 14, 2007 one thing that bugs me about c++ | ||||
|---|---|---|---|---|
| ||||
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? | ||||
December 14, 2007 Re: one thing that bugs me about c++ | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Neal Becker | 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.
| |||
December 14, 2007 Re: one thing that bugs me about c++ | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Neal Becker | 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
| |||
December 14, 2007 Re: one thing that bugs me about c++ | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | 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>()) ) | |||
December 14, 2007 Re: one thing that bugs me about c++ | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Neal Becker | 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.
| |||
December 14, 2007 Re: one thing that bugs me about c++ | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Neal Becker | 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.
| |||
December 14, 2007 Re: one thing that bugs me about c++ | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Neal Becker | 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
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply