
"Toon Knapen" <toon.knapen@fft.be> escribió en el mensaje news:4295AA07.5030102@fft.be...
Following small program does not give the expected result. It prints some big negative value if compiled with my gcc 3.4.3 on linux or intel-linux 8.1.
However commenting out either (one suffices) of the commented out lines makes it work correctly. I don't understand what is happening here, can anybody what is wrong with this function 'convert' or is the use of the conversion library wrong?
<code> #include <boost/numeric/conversion/cast.hpp> #include <iostream>
template<typename Target, typename Source> inline typename ::boost::numeric::converter<Target,Source>::result_type //convert ( const Source& arg ) // using this signatures makes it work convert ( Source arg ) { return ::boost::numeric::converter< Target, Source >::convert( arg ) ; } // { Target temp = ::boost::numeric::converter< Target, Source
::convert( arg ) ; return temp ; }
int main() { int big = 900 ; ptrdiff_t diff = 16 ; std::cout << std::min( big, convert< int >( diff ) ) << std::endl ;
return 0 ; } </code>
OK, this is a good one :-) Whenever Source==Target, the library attempts to reduce the conversion to a no-op; That is, for the following code: numeric::converter<int,int>::convert(123); the instantiated convert function is this: int const& convert( int const& s ) { return s ; } Notice that it takes a reference and returns a reference. As such, numeric::converter<int,int>::result_type is "int const&"; that is, a reference. and: numeric::converter<int,int>::argument_type is also "int const&" Now... you've wrapped that function into your own, which after all the template instantiations is equivalent to: int const& your_convert( int s ) { return s ; } Now, combine this with std::min() (or any other template using argument-type deduction) and the argument becomes "int const&" which explains your unexpected results. A "fix" on your side would be to use ::boost::numeric::converter<Target,Source>::argument_type; but this isn't practical because users are forced to specify "Source" explicitely. So you need "Source" to be the source type, but then, you also _need_ "Target" to be the result type: template<typename Target, typename Source> inline Target convert2 ( Source arg ) { return ::boost::numeric::converter< Target, Source >::convert( arg ) ; } Incidentally, boost::numeric_cast<> (the new one) is equivalent to your code so is just as equally buggy. I'm afraid I have to patch it not to use result_type anymore. P.S: One could thing that the traits class, in the case of a trivial conversion, could define bare types instead of references (that is, making result_type being just "T" instead of "T const&). Altough this OK for builtin types, it isn't for the UDT, and it is precisly in the case of UDTs were the "reduction to a no-op in the trivial case" becomes really important. This means though that numeric_cast<> is better not used with UDTs in generic context when T==S is possible (because the optimization is then lost) P.S.2: Of course the alternative is to use "Source const&" instead of "Source"... I don't really remember the details but I seem to recall that the original numeric_cast<> used a non-reference argument for some good reason; and so I just kept that. Thanks for the report! Fernando Cacciola SciSoft