Travis Gockel
Travis Gockel

Reputation: 27633

BOOST_STATIC_WARNING

I've recently had some trouble with C++'s implicit casting, so I'm looking for a way to warn people if somebody attempts to assign an int32_t to a uint64_t or whatever. BOOST_STATIC_ASSERT would work wonders for this, except that the code base I'm working with is quite large and relies on a lot of implicit casting, so immediately breaking everything with assertions is unrealistic.

It looks like BOOST_STATIC_WARNING would be ideal for me, however, I cannot get it to actually emit a warning. Something like this won't do anything:

    typedef boost::is_same<int64_t, int32_t> same_type;
    BOOST_STATIC_WARNING(same_type::value);

My compiler is g++ 4.4.3 with --std=c++0x -Wall -Wextra. My Boost is 1.46.1.


The problem I'm trying to solve here is that we have a buffer type which has methods like uint8_t GetUInt8(size_type index), void SetUInt32(size_type index, uint32_t value), etc. So, you see usage like this:

x = buffer.GetUInt16(96);

The problem is that there is no guarantee that, while you are reading a 16-bit unsigned integer, that x is actually 16-bits. While the person who originally wrote that line did it properly (hopefully), if the type of x changes, this line will break silently.

My solution is to create a safe_convertable<T> type like so:

template <typename T>
struct safe_convertable
{
public:
    template <typename TSource>
    safe_convertable(const TSource& val)
    {
        typedef boost::is_same<T, TSource> same_type;
        BOOST_STATIC_WARNING(same_type::value);

        _val = val;
    }

    template <typename TDestination>
    operator TDestination ()
    {
        typedef boost::is_same<T, TDestination> same_type;
        BOOST_STATIC_WARNING(same_type::value);

        return _val;
    }
private:
    T _val;
};

and change the methods to return and accept these safe references: safe_reference<uint8_t> GetUInt8(size_type index), void SetUInt32(size_type index, safe_reference<uint32_t> value) (that's the short version, there are other operators and whatnot you can do to references).

Anyway, this works great with BOOST_STATIC_ASSERT, save for the fact that I want warnings and not errors.


For the curious, I've implemented the warning thing myself, which works fine, but I'd prefer the Boost variety so that I get all the other Boost features (this only works inside a function).

namespace detail
{
    template <typename TIntegralContant>
    inline void test_warning(const TIntegralContant&)
    {
        static_cast<void>(1 / TIntegralContant::value);
    }
}

#define MY_STATIC_WARNING(value_) \
    ::detail::test_warning(::boost::integral_constant<bool, value_ >())

Upvotes: 4

Views: 1101

Answers (1)

Sean
Sean

Reputation: 10206

What version of Boost are you using? This comment may be the reason why your own warning works, but the boost version does not:

// 6. replaced implementation with one which depends solely on
//    mpl::print<>.  The previous one was found to fail for functions
//    under recent versions of gcc and intel compilers - Robert Ramey

I'm guessing if you upgraded to a recent version of Boost (e.g. 1.46.1), you'd be good to go. crosses fingers

Upvotes: 1

Related Questions