Topic: Restricting type deduction
Author: kalleunderscorerutanen@hotmail.com (Kaba)
Date: Tue, 13 Mar 2007 14:50:29 GMT Raw View
I'd like to discuss about the feasiblity of adding a way to restrict the
type deduction system with templates. I sometimes find that I am not
able to accurately express the desired functionality in the current C++.
For example, consider:
FloatVector operator*(const float& left, const FloatVector& right)
{
return right * left;
}
How do you make up a templatized version of this that works for the
float type _exactly_ as this normal function?
Well, we have discussed this here before, here's the answer:
http://kaba.hilvi.org/project/mycents/mycents3.htm
Note the important observation: there is no way to define that
generalized function out-of-class. This has consequences of making it
hard to implement left-hand binary operators, which should be, in my
opinion, as easy as implementing the right-hand binary operators.
Actually, this problem is strongly connected with implicit conversions.
While implicit conversions might be bad in general, they are heavily
used with native types because one uses various literals when giving
fixed input such as f(0.5, 3, 3.0f). That these literals do have an
associated type brings problems to using them with templates. The
problem with template functions is that they lose the ability to do
implicit conversions to the parameters.
While the current status is that template functions lose all of the
implicit conversion opportunities, I propose that there be provided a
way to allow some of those. The idea is to allow disabling type
deduction on a per parameter basis. This way the left-hand binary
operator would be implemented as:
template <typename Real>
Vector<Real> operator*(private: const Real& left, const Vector<Real>&
right);
Which correctly models the normal-function case: with the right hand
type Vector<float>, Real is deduced to be float. This can be defined
out-of-class.
Another example, consider:
template <typename Real>
void quantize(const Array2<Real>& input, Array2<Real>& output, const
Real& quantization);
You call this as:
Array2<float> input;
Array2<float> output;
quantize(input, output, 0.1);
And blam, you just created a compiler error.
Consider you fixed this problem as:
quantize(input, output, (float)0.1);
Now it works, but what if later someone changes the arrays to use
double:
Array2<double> input;
Array2<double> output;
quantize(input, output, (float)0.1);
Not again a compiler error!
Well, maybe you were wiser and had a typedef for the used types:
typedef double Real;
Array2<Real> input;
Array2<Real> output;
quantize(input, output, (Real)0.1);
Ok, now it works. Even if you changed Real to some other type.
But just look at that function call. Isn't it embarassing that you need
to specify explicitly that you really mean a Real type? You yourself
know that the 0.1 is just a number: that's the precision you are giving
it, its the functions responsibility to convert it to its own purposes.
Well, you could go on generalizing:
template <typename Real, typename Real2>
void quantize(const Array2<Real>& input, Array2<Real>& output, const
Real2& quantization);
But now, that doesn't automatically create equivalent code as compared
to the first: you need to simulate the implicit conversion to Real to
achieve that!
These issues are really annoying, and they are common: this is because
native types are used all the time during the development.
I'd rather like the following:
template <typename Real>
void quantize(const Array2<Real>& input, Array2<Real>& output, private:
const Real& quantization);
Array2<float> input;
Array2<float> output;
quantize(input, output, 0.1);
Success!
Now, there might be unexpected consequences from this and this is just
one proposal to handle this problem. Anyway, for all my experience, I
find that this problem is an annoying one and really should be addressed
for the upcoming standard.
--
Kalle Rutanen
http://kaba.hilvi.org
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: yechezkel@emailaccount.com (Yechezkel Mett)
Date: Tue, 13 Mar 2007 16:45:44 GMT Raw View
Kaba wrote:
> While the current status is that template functions lose all of the
> implicit conversion opportunities, I propose that there be provided a
> way to allow some of those. The idea is to allow disabling type
> deduction on a per parameter basis. This way the left-hand binary
> operator would be implemented as:
>
> template <typename Real>
> Vector<Real> operator*(private: const Real& left, const Vector<Real>&
> right);
>
> Which correctly models the normal-function case: with the right hand
> type Vector<float>, Real is deduced to be float. This can be defined
> out-of-class.
template<typename T>
struct nondeduced
{
typedef T type;
};
template<typename Real>
Vector<Real operator*(typename nondeduced<Real>::type& left, const
Vector<Real>& right);
Yechezkel Mett
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Kaba <kalleunderscorerutanen@hotmail.com>
Date: Tue, 13 Mar 2007 14:18:48 CST Raw View
> template<typename T>
> struct nondeduced
> {
> typedef T type;
> };
>
> template<typename Real>
> Vector<Real operator*(typename nondeduced<Real>::type& left, const
> Vector<Real>& right);
Impressive! I love this group. Thank you for showing a solution I didn't
thought to exist.
--
Kalle Rutanen
http://kaba.hilvi.org
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]