|
Boost : |
Subject: Re: [boost] Regression test relying on undefined compiler behavior (c++11)
From: Chris Cooper (chris.cooper_at_[hidden])
Date: 2014-04-23 16:48:17
After the builds finally chugged through the build server, I see that std::numeric_limits<Number>::min() and std::numeric_limits<Number>::max() are not constant expressions with clang++ unless c++11 is enabled, so my second idea wont quite work.
From: Chris Cooper <chris.cooper_at_[hidden]<mailto:chris.cooper_at_[hidden]>>
Date: Wednesday, April 23, 2014 at 12:20 PM
To: "boost_at_[hidden]<mailto:boost_at_[hidden]>" <boost_at_[hidden]<mailto:boost_at_[hidden]>>
Subject: Re: Regression test relying on undefined compiler behavior (c++11)
Actually, I came up with a better idea:
#ifndef BOOST_NO_LIMITS
template <class Number> struct complement_traits
{
BOOST_STATIC_CONSTANT(Number, min = std::numeric_limits<Number>::min());
BOOST_STATIC_CONSTANT(Number, max = std::numeric_limits<Number>::max());
};
#else
[SNIP] All the other template stuff for calculating complement_traits for various types
#endif
From: Chris Cooper <chris.cooper_at_[hidden]<mailto:chris.cooper_at_[hidden]>>
Date: Wednesday, April 23, 2014 at 11:59 AM
To: "boost_at_[hidden]<mailto:boost_at_[hidden]>" <boost_at_[hidden]<mailto:boost_at_[hidden]>>
Subject: Regression test relying on undefined compiler behavior (c++11)
libs/utility/numeric_traits_test.cpp generates values complement_traits<Number>::min using a clever recursive template, but that template relies on left-shifting a negative value, and according to the C++11 standard thats a no-no (the behavior is undefined) which means its not a constant expression, which means it cant be calculated at compile time, which means the BOOST_STATIC_ASSERT in line 332 wont compile, saying static_assert expression is not an integral constant expression (Im using clang++).
See discussion here: http://stackoverflow.com/questions/23250651/strange-behavior-with-c-recursive-templates-when-c11-is-enabled
In addition, it looks like the existing code also relies on the compiler filling the vacated bits with ones, which I dont think is what actually happens.
The solution Ive come up with, is to do the shifting using unsigned values, thus avoiding the compiler no-no, and then putting the result back in the specified type. In other words, replacing line 73
BOOST_STATIC_CONSTANT(Number, min = Number(Number(prev::min) << CHAR_BIT));
With
BOOST_STATIC_CONSTANT(Number, min = boost::detail::is_signed<Number>::value ? (Number)(((unsignedlong)(prev::min) << 8) | 0x00FF) : Number(Number(prev::min) << CHAR_BIT) );
Im using constants 8 and 0x00FF rather than CHAR_BIT since the code would get really ugly if CHAR_BIT != 8.
Thoughts?
Thanks,
Chris
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk