惊艳的效果还在继续,第二章开始讲到了一些基本的传统的(但是我居然还是不知道的)技法,利用模板的编译特殊编译特性带来了些新的帮助。
有印象的东西就是Compile-time assertions, 和Traits。
Assert 是个很奇特的东西,说实话就是在debug的时候有点用处,因为在release中如果Assert失败抛出个什么错误对话框也一点都不make sense。但是如果可以帮debug时候的crash编程编译期间就能查到的错误,也是一个不错的选择。故此才有了这样的想法。
其实这个compile-time assertions不是一个很新的东西,找了看看里面Loki的实现:
namespace Loki
{
// Helper structure for the STATIC_CHECK macro
template struct CompileTimeError;
template<> struct CompileTimeError {};
}
// macro STATIC_CHECK
// Invocation: STATIC_CHECK(expr, id)
// where:
// expr is a compile-time integral or pointer expression
// id is a C++ identifier that does not need to be defined
// If expr is zero, id will appear in a compile-time error message.
#define LOKI_STATIC_CHECK(expr, msg) /
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
其 实这个实现到Loki::CompileTimeError<((expr) != 0)>这一步已经够了,但是如果加上了ERROR_##msg以后就更有说明性,boost里面应该也有一个类似的实现叫做 BOOST_STATIC_ASSERT。有兴趣可以去查查看。
说玩这个assert,我们来看看traits,这个在STL中有经典应用的东西。在这里首先援引Scott Mayer的一段评价: Traits are basically compile-time else-if-thens: the unspecialized template is the else clause, the specializations are the if clauses. I think traits can be used to determine whether a template parameter is a built-in type. Also whether a template parameter inherits from a given base class. The trick is to create a template generating code that won't compile, then provide specializations that *will* compile for the special cases that are allowed.
Traits被称为一个基于编译器的 if-else选择,(这章的主题就是在编译期间可以尽量多做一点动态运行时才做的事情)。利用模板的partial specification,可以很好的在编译期间完成对具体类型的instantiation,找到最高效的实现。在这里贴出一点VS STL中iterator_traits的部分定义:
// TEMPLATE CLASS iterator_traits
template struct iterator_traits
{ // get traits from iterator _Iter
typedef typename _Iter::iterator_category iterator_category;
typedef typename _Iter::value_type value_type;
typedef typename _Iter::difference_type difference_type;
typedef difference_type distance_type; // retained
typedef typename _Iter::pointer pointer;
typedef typename _Iter::reference reference;
};
template struct iterator_traits<_ty>
{ // get traits from pointer
typedef random_access_iterator_tag iterator_category;
typedef _Ty value_type;
typedef ptrdiff_t difference_type;
typedef ptrdiff_t distance_type; // retained
typedef _Ty *pointer;
typedef _Ty& reference;
};
template struct iterator_traits
{ // get traits from const pointer
typedef random_access_iterator_tag iterator_category;
typedef _Ty value_type;
typedef ptrdiff_t difference_type;
typedef ptrdiff_t distance_type; // retained
typedef const _Ty *pointer;
typedef const _Ty& reference;
};
template<> struct iterator_traits<_bool>
{ // get traits from integer type
typedef _Int_iterator_tag iterator_category;
typedef _Bool value_type;
typedef _Bool difference_type;
typedef _Bool distance_type;
typedef _Bool * pointer;
typedef _Bool& reference;
};
template<> struct iterator_traits
{ // get traits from integer type
typedef _Int_iterator_tag iterator_category;
typedef char value_type;
typedef char difference_type;
typedef char distance_type;
typedef char * pointer;
typedef char& reference;
};
template<> struct iterator_traits
{ // get traits from integer type
typedef _Int_iterator_tag iterator_category;
typedef signed char value_type;
typedef signed char difference_type;
typedef signed char distance_type;
typedef signed char * pointer;
typedef signed char& reference;
};
在这里的定义是不完整的,但是我们已经可以看出一些端倪了, iterator_traits这个类有了很多的partial specification的定义,我们这里有指针, const 指针,char, bool等等, 很明显的是 pointer, value_type这样的类型会由于不同的类型而产生不错定义,这样就完成对不同类型的优化和特殊实现。如果我们在看看某个函数的
template inline
typename iterator_traits<_init>::difference_type
__CLRCALL_OR_CDECL distance(_InIt _First, _InIt _Last)
{ // return distance between iterators
typename iterator_traits<_init>::difference_type _Off = 0;
_Distance2(_First, _Last, _Off, _Iter_cat(_First));
return (_Off);
}
注意这个函数的_Iter_cat函数,这里是他的实现:
template inline
typename iterator_traits<_iter>::iterator_category
__CLRCALL_OR_CDECL _Iter_cat(const _Iter&)
{ // return category from iterator argument
typename iterator_traits<_iter>::iterator_category _Cat;
return (_Cat);
}
实际上返回的类型的就是当初的_First这个iterator_traits<_init>的iterator_category类型,根据这个类型的不同就可以有多个实现了:
template inline
void __CLRCALL_OR_CDECL _Distance2(_RanIt _First, _RanIt _Last, _Diff& _Off,
random_access_iterator_tag)
{ // add to _Off distance between random-access iterators
#if _HAS_ITERATOR_DEBUGGING
if (_First != _Last)
{ // check for null pointers
_DEBUG_POINTER(_First);
_DEBUG_POINTER(_Last);
}
#endif /* _HAS_ITERATOR_DEBUGGING */
_Off += _Last - _First;
}
template inline
void __CLRCALL_OR_CDECL _Distance2(_InIt _First, _InIt _Last, _Diff& _Off,
input_iterator_tag)
{ // add to _Off distance between input iterators
for (; _First != _Last; ++_First)
++_Off;
}
template inline
void __CLRCALL_OR_CDECL _Distance2(_FwdIt _First, _FwdIt _Last, _Diff& _Off,
forward_iterator_tag)
{ // add to _Off distance between forward iterators (redundant)
for (; _First != _Last; ++_First)
++_Off;
}
可以看到的是random access比之其他还是高效不少的。STL中的这些一iterator作为参数的函数相信都是利用这样的 traits类型判断而实现了最适合当前类型的函数,从而是实现达到最高效。
其实这里写到的只是traits的一点点的应用,相信在这本书阅读的过程中还有更多更强大的traits在Loki中的应用,应该慢慢呈现出来。编程真是一门艺术!
有印象的东西就是Compile-time assertions, 和Traits。
Assert 是个很奇特的东西,说实话就是在debug的时候有点用处,因为在release中如果Assert失败抛出个什么错误对话框也一点都不make sense。但是如果可以帮debug时候的crash编程编译期间就能查到的错误,也是一个不错的选择。故此才有了这样的想法。
其实这个compile-time assertions不是一个很新的东西,找了看看里面Loki的实现:
namespace Loki
{
// Helper structure for the STATIC_CHECK macro
template struct CompileTimeError;
template<> struct CompileTimeError {};
}
// macro STATIC_CHECK
// Invocation: STATIC_CHECK(expr, id)
// where:
// expr is a compile-time integral or pointer expression
// id is a C++ identifier that does not need to be defined
// If expr is zero, id will appear in a compile-time error message.
#define LOKI_STATIC_CHECK(expr, msg) /
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
其 实这个实现到Loki::CompileTimeError<((expr) != 0)>这一步已经够了,但是如果加上了ERROR_##msg以后就更有说明性,boost里面应该也有一个类似的实现叫做 BOOST_STATIC_ASSERT。有兴趣可以去查查看。
说玩这个assert,我们来看看traits,这个在STL中有经典应用的东西。在这里首先援引Scott Mayer的一段评价: Traits are basically compile-time else-if-thens: the unspecialized template is the else clause, the specializations are the if clauses. I think traits can be used to determine whether a template parameter is a built-in type. Also whether a template parameter inherits from a given base class. The trick is to create a template generating code that won't compile, then provide specializations that *will* compile for the special cases that are allowed.
Traits被称为一个基于编译器的 if-else选择,(这章的主题就是在编译期间可以尽量多做一点动态运行时才做的事情)。利用模板的partial specification,可以很好的在编译期间完成对具体类型的instantiation,找到最高效的实现。在这里贴出一点VS STL中iterator_traits的部分定义:
// TEMPLATE CLASS iterator_traits
template struct iterator_traits
{ // get traits from iterator _Iter
typedef typename _Iter::iterator_category iterator_category;
typedef typename _Iter::value_type value_type;
typedef typename _Iter::difference_type difference_type;
typedef difference_type distance_type; // retained
typedef typename _Iter::pointer pointer;
typedef typename _Iter::reference reference;
};
template struct iterator_traits<_ty>
{ // get traits from pointer
typedef random_access_iterator_tag iterator_category;
typedef _Ty value_type;
typedef ptrdiff_t difference_type;
typedef ptrdiff_t distance_type; // retained
typedef _Ty *pointer;
typedef _Ty& reference;
};
template struct iterator_traits
{ // get traits from const pointer
typedef random_access_iterator_tag iterator_category;
typedef _Ty value_type;
typedef ptrdiff_t difference_type;
typedef ptrdiff_t distance_type; // retained
typedef const _Ty *pointer;
typedef const _Ty& reference;
};
template<> struct iterator_traits<_bool>
{ // get traits from integer type
typedef _Int_iterator_tag iterator_category;
typedef _Bool value_type;
typedef _Bool difference_type;
typedef _Bool distance_type;
typedef _Bool * pointer;
typedef _Bool& reference;
};
template<> struct iterator_traits
{ // get traits from integer type
typedef _Int_iterator_tag iterator_category;
typedef char value_type;
typedef char difference_type;
typedef char distance_type;
typedef char * pointer;
typedef char& reference;
};
template<> struct iterator_traits
{ // get traits from integer type
typedef _Int_iterator_tag iterator_category;
typedef signed char value_type;
typedef signed char difference_type;
typedef signed char distance_type;
typedef signed char * pointer;
typedef signed char& reference;
};
在这里的定义是不完整的,但是我们已经可以看出一些端倪了, iterator_traits这个类有了很多的partial specification的定义,我们这里有指针, const 指针,char, bool等等, 很明显的是 pointer, value_type这样的类型会由于不同的类型而产生不错定义,这样就完成对不同类型的优化和特殊实现。如果我们在看看某个函数的
template inline
typename iterator_traits<_init>::difference_type
__CLRCALL_OR_CDECL distance(_InIt _First, _InIt _Last)
{ // return distance between iterators
typename iterator_traits<_init>::difference_type _Off = 0;
_Distance2(_First, _Last, _Off, _Iter_cat(_First));
return (_Off);
}
注意这个函数的_Iter_cat函数,这里是他的实现:
template inline
typename iterator_traits<_iter>::iterator_category
__CLRCALL_OR_CDECL _Iter_cat(const _Iter&)
{ // return category from iterator argument
typename iterator_traits<_iter>::iterator_category _Cat;
return (_Cat);
}
实际上返回的类型的就是当初的_First这个iterator_traits<_init>的iterator_category类型,根据这个类型的不同就可以有多个实现了:
template inline
void __CLRCALL_OR_CDECL _Distance2(_RanIt _First, _RanIt _Last, _Diff& _Off,
random_access_iterator_tag)
{ // add to _Off distance between random-access iterators
#if _HAS_ITERATOR_DEBUGGING
if (_First != _Last)
{ // check for null pointers
_DEBUG_POINTER(_First);
_DEBUG_POINTER(_Last);
}
#endif /* _HAS_ITERATOR_DEBUGGING */
_Off += _Last - _First;
}
template inline
void __CLRCALL_OR_CDECL _Distance2(_InIt _First, _InIt _Last, _Diff& _Off,
input_iterator_tag)
{ // add to _Off distance between input iterators
for (; _First != _Last; ++_First)
++_Off;
}
template inline
void __CLRCALL_OR_CDECL _Distance2(_FwdIt _First, _FwdIt _Last, _Diff& _Off,
forward_iterator_tag)
{ // add to _Off distance between forward iterators (redundant)
for (; _First != _Last; ++_First)
++_Off;
}
可以看到的是random access比之其他还是高效不少的。STL中的这些一iterator作为参数的函数相信都是利用这样的 traits类型判断而实现了最适合当前类型的函数,从而是实现达到最高效。
其实这里写到的只是traits的一点点的应用,相信在这本书阅读的过程中还有更多更强大的traits在Loki中的应用,应该慢慢呈现出来。编程真是一门艺术!