У меня недавно были некоторые проблемы с неявным приведением C ++, поэтому я ищу способ предупредить людей, если кто-то пытается присвоить int32_t для uint64_t или чего-то еще. BOOST_STATIC_ASSERT
будет творить чудеса для этого, за исключением того, что кодовая база, с которой я работаю, достаточно велика и опирается на множество неявных приведений, поэтому немедленное нарушение всего с помощью утверждений нереально.
Похоже, BOOST_STATIC_WARNING было бы идеально для меня, однако я не могу заставить его на самом деле выдать предупреждение. Что-то вроде этого ничего не сделает:
typedef boost::is_same<int64_t, int32_t> same_type;
BOOST_STATIC_WARNING(same_type::value);
Мой компилятор g ++ 4.4.3 с --std = c ++ 0x -Wall -Wextra. Мой буст 1.46.1.
Проблема, которую я пытаюсь решить, состоит в том, что у нас есть тип буфера, который имеет такие методы, как uint8_t GetUInt8(size_type index)
, void SetUInt32(size_type index, uint32_t value)
и т. Д. Итак, вы видите использование следующим образом:
x = buffer.GetUInt16(96);
Проблема в том, что нет гарантии, что, пока вы читаете 16-разрядное целое число без знака, x
на самом деле является 16-разрядным. Хотя тот, кто первоначально написал эту строку, сделал это правильно (надеюсь), если тип x
изменится, эта строка будет молча прерываться.
Мое решение состоит в том, чтобы создать тип safe_convertable<T>
следующим образом:
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;
};
и измените методы для возврата и принятия этих безопасных ссылок: safe_reference<uint8_t> GetUInt8(size_type index)
, void SetUInt32(size_type index, safe_reference<uint32_t> value)
(это краткая версия, есть другие операторы и все, что вы можете сделать со ссылками).
В любом случае, это прекрасно работает с BOOST_STATIC_ASSERT
, за исключением того факта, что мне нужны предупреждения, а не ошибки.
Для любопытных я сам реализовал функцию предупреждения, которая отлично работает, но я бы предпочел вариант Boost, чтобы получить все остальные функции Boost (это работает только внутри функции).
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_ >())