编译器检查
特点:
- 静态类型检查
- 可定制类型错误消息
例子:实现安全转型的函数,并确保较大型别不能转换成较小型别。 迭代一
template <typename To, typename From>
To safe_reinterpret_cast(From from)
{
assert(sizeof(From) < sizeof(To));
return reinterpret_cast<To>(from) ;
}
上述代码,会在执行期进行断言。 迭代二 期待编译期识别出错误,利用编译器做类型安全检查 方案一: 利用基本语法规则:大小为零的数组是非法的。
#define STATIC_ASSERT(expr) { char unnamed[(expr) ? 1 : 0]; }
template <typename To, typename From>
To safe_reinterpret_cast(From from)
{
STATIC_ASSERT(sizeof(From) < sizeof(To));
return reinterpret_cast<To>(from) ;
}
如果尝试将int*类型转换成char类型,书上说编译器将抱怨“正试着产生一个长度为零的数组”。
int* i = new int(100);
char ch = safe_reinterpret_cast<char>(i);
但新的编译器已经能完全给出更加易理解的信息:
<source>: In instantiation of 'To safe_reinterpret_cast(From) [with To = char; From = int*]':
<source>:21:40: required from here
<source>:14:9: error: cast from 'int*' to 'char' loses precision [-fpermissive]
return reinterpret_cast<To>(from) ;
方案二 利用模板特化,提供带有特定意义的 template类型名称,出错时编译器能打印出template类型名称。
template<bool> struct CompileTimeError;
template<> struct CompileTimeError<true> { };
#define STATIC_ASSERT(expr) (CompileTimeError<(expr)>())
上面使用,编译失败信息如下:
<source>:10:30: error: invalid use of incomplete type 'struct CompileTimeError<false>'
#define STATIC_ASSERT(expr) (CompileTimeError<(expr)>())
~^~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:15:2: note: in expansion of macro 'STATIC_ASSERT'
STATIC_ASSERT(sizeof(From) < sizeof(To));
^~~~~~~~~~~~~
<source>:8:23: note: declaration of 'struct CompileTimeError<false>'
template<bool> struct CompileTimeError;
从上述错误提示信息看出,CompileTimeError提示还没有表示出具体的意义。 迭代三 改良错误提示信息
template<bool>
struct CompileTimeChecker
{
CompileTimeChecker( ...);
};
template<>
struct CompileTimeChecker<false>
{};
#define STATIC_ASSERT(expr, msg) \
{ \
class ERROR_##msg{}; \
(void)sizeof(CompileTimeChecker<(expr)>(ERROR_##msg( ))); \
}
template <typename To, typename From>
To safe_reinterpret_cast(From from)
{
STATIC_ASSERT(sizeof(From) < sizeof(To), destination_type_too_narrow);
return reinterpret_cast<To>(from);
}
上例中编译出错提示信息:
<source>:27:2: note: in expansion of macro 'STATIC_ASSERT'
STATIC_ASSERT(sizeof(From) < sizeof(To), destination_type_too_narrow);
能明确提示具体错误原因。
|