Boost logo

Boost Users :

From: Daryle Walker (darylew_at_[hidden])
Date: 2005-12-12 01:53:49


On 12/10/05 10:55 PM, "Andrew n marshall" <amarshal_at_[hidden]> wrote:

> I've encountered a problem when transitioning from Boost.Test 1.32 to
> 1.33. New to 1.33 is a set_precision(..) method on the print_log_value
> functor (in test_tools.hpp). The problem, as I see it, is the use of
> numeric_limits<T>, which exposes the assumption T is a numeric entity at
> all. I'm actually surprised it compiles as often as it does, so maybe
> my blame is misdirected. Nonetheless, I was able to create the attached
> test case to prove my point. I've also included the generated build log
> with the really nasty compile time error.
[TRUNCATE Mr. Marshall's code example]

Your blame may be misdirected. Looking at the Boost.Test code:

    template<typename T>
    struct print_log_value {
        void operator()( std::ostream& ostr, T const& t )
        {
            typedef typename mpl::or_<is_array<T>,is_function<T>
>::type couldnt_use_nl;

            set_precision( ostr, couldnt_use_nl() );

            ostr << t; // by default print the value
        }

        void set_precision( std::ostream& ostr, mpl::false_ )
        {
            if( std::numeric_limits<T>::is_specialized
             && std::numeric_limits<T>::radix == 2 )
                ostr.precision( 2 + std::numeric_limits<T>::digits
                 * 301/1000 );
        }

        void set_precision( std::ostream&, mpl::true_ ) {}
    };

it uses std::numeric_limits<>::is_specialized to make sure that the
precision is set only for numeric types. Otherwise, that function does
nothing. The functor's operator() splits the code according to type, and
types that don't even make it to the set_precision you're talking about also
do nothing. Actually, since the is_specialized field should be a
compile-time constant, the code should be shifted to compile-time even
further:

    template<typename T>
    struct print_log_value {
        void operator()( std::ostream& ostr, T const& t )
        {
            typedef typename mpl::or_<is_array<T>,is_function<T>,
             mpl::bool_<!std::numeric_limits<T>::is_specialized>
>::type couldnt_use_nl;

            set_precision( ostr, couldnt_use_nl() );

            ostr << t; // by default print the value
        }

        void set_precision( std::ostream& ostr, mpl::false_ )
        {
            ostr.precision( 2 + std::numeric_limits<T>::digits * 301/1000 );
        }

        void set_precision( std::ostream&, mpl::true_ ) {}
    };

Of course, this code assumes that std::numeric_limits<>::radix is 2. The
301/1000 is a logarithm conversion factor to turn a power of 2 into a power
of 10, with two extra digits for slop. This lets us print out a number to
all of its defined digits in decimal. Maybe more compile-time conditions
should be added to confirm those assumptions. Any type that doesn't pass
the test is assumed to be non-numeric and hopefully will print out enough of
its state to be unambiguous without setting the precision.

As far as your code is concerned, I think it should work. You always should
be able to convert pointers/references to a base class, even if it's
abstract. And you should be able to work/channel through those pointers and
references. The only thing pure-virtual member functions block is creating
an object directly of the abstract type. But I don't see any slice & copy
action here.

-- 
Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT hotmail DOT com

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net