"Toon Knapen" 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
#include <iostream>
template
inline
typename ::boost::numeric::converter::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::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::result_type is "int const&"; that is, a
reference.
and:
numeric::converter::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::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
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