テンプレートのTypeTraits

4698 ワード

Traitsは、実行期間中に数値に基づいて判断を実行するように、コンパイラが型別に基づいて判断するのに使用できる汎用技術です.
Traitsの利点:「型別が確立された当時」の意外な他の場所で型別に関する判断を下すことができます.これにより、コードがよりきれいになり、より読み取り可能になり、メンテナンスが向上します.

1実作Pointer Traits

//   NullType   EmptyType
class NullType;
struct EmptyType {}; 

template <typename T>
class TypeTraits
{
private:
	template <class U> struct PointerTraits //  , 
	{
		enum { result = false };
		typedef NullType PointeeType;
	};
	template <class U> struct PointerTraits<U*> //  
	{
		enum { result = true };
		typedef U PointeeType; // T  ,  T  ,NOT Pointer!!!
	};
public:
	enum { isPointer = PointerTraits<T>::result };
	typedef typename PointerTraits<T>::PointeeType PointeeType; // typename  !!
};
同様に、template traitsでpointers to membersを判断できます.
template <typename T>
class TypeTraits
{
private:
	// pointers to members
	template <class U> struct PToMTraits
	{
		enum { result = false };
	};
	template <class U, class V>
	struct PToMTraits < U V::* >
	{
		enum { result = true };
	};

	// stripping qualifiers ( )
	template <class U> struct UnConst
	{
		typedef U Result;
	};
	template <class U> struct UnConst <const U>
	{
		typedef U Result;
	};
public:
	enum { isMemberPointer = PToMTraits<T>::result };
};

2最適化されたパラメータタイプ


汎用コードでは、任意の型別Tが与えられ、「Tオブジェクトの伝達関数をパラメータとする」最も効果的な方法は何ですか.
一般的に、最も効果的な方法は、精巧な型別が伝達されるときにby reference伝達方式を採用し、純量型別に直面するときにby value伝達方式を採用することである.
スカラー・カテゴリは、数値カテゴリ、列挙カテゴリ、ポインタ、メンバーを指すポインタから構成されます.
精巧なカテゴリは、カスタムタイプstructまたはclassから構成されます.
精巧な型別は、追加の一時オブジェクトによる追加のオーバーヘッド(構造関数と構造関数の追加呼び出し動作)を回避する必要があります.純量型別はreferenceによる間接性による余分なオーバーヘッドを避けるべきである.
注意:C++はreferences to referencesを許可しません.したがって,Tが既にreferenceであれば,それにreferenceを加えてはいけない.

3消しゴム

template <typename T>
class TypeTraits
{
private:
	// stripping qualifiers ( )
	template <class U> struct UnConst
	{
		typedef U Result;
	};
	template <class U> struct UnConst <const U>
	{
		typedef U Result;
	};
public:	
	typedef typename UnConst<T>::Result NonConstType;
};

4 TypeTraitsの運用

enum CopyAlgoSelector { Conservative, Fast };

// Conservative routine-works for any type
template <typename InIt, typename OutIt>
OutIt CopyImpl(InIt first, InIt last, OutIt result, Int2Type<Conservative>)
{
	for (; first != last; ++first, ++result)
		*result = *first
}
// Fast routine-works only for pointers to raw data
template <typename InIt, typename OutIt>
OutIt CopyImpl(InIt first, InIt last, OutIt result, Int2Type<Fast>)
{
	const size_t n = last - first;
	memcpy(result, first, n*sizeof(*first));
	return result + n;
}
template <typename InIt, typename OutIt>
OutIt Copy(InIt first, InIt last, OutIt result)
{
	typedef TypeTraits<InIt>::PointeeType SrcPointee;
	typedef TypeTraits<OutIt>::PointeeType DestPointee;
	enum { copyAlgo = 
		TypeTraits<InIt>::isPointer &&
		TypeTraits<OutIt>::isPointer &&
		TypeTraits<SrcPointee>::isStdFundamental &&  //   typelist 
		TypeTraits<DestPointee>::isStdFundamental &&
		sizeof(SrcPointee) == sizeof(DestPointee) ? Fast : Conservative };

	return CopyImpl(first, last, result, Int2Type<copyAlgo>);
}
enum copyAlgoは、反復器がポインタであり、基本型を指し、型の大きさが同じである場合、memcpyを使用するアルゴリズムを自動的に選択します.
もしあなたがそうすれば:
int*p1 = ...
int* p2 =..
usigned int* p3 = ..
Copy(p1, p2, p3); // Copy()  , “ ”   “ ” 。
基本タイプからなるデータ、いわゆるplain old dataまたはPOD構造をC structと仮定します.C++はPODに対してbitwise copy(ビット毎コピー)動作を行うことができるが、Copy()は操作対象がPODであるか否かを判断できないため、スローバージョンを呼び出す.あなたはそうするしかありません.
template <typename T> struct SupportsBitwiseCopy
{
	enum { result = TypeTraits<T>::isStddFundamental };
};
template <typename InIt, typename OutIt>
OutIt Copy(InIt first, InIt last, OutIt result, int2Type<true>)
{
	typedef TypeTraits<InIt>::PointeeType SrcPointee;
	typedef TypeTraits<OutIt>::PointeeType DestPointee;
	enum { useFast = 
		TypeTraits<InIt>::isPointer &&
		TypeTraits<OutIt>::isPointer &&
		SupportsBitwiseCopy<SrcPointee>::result &&  //   typelist 
		SupportsBitwiseCopy<DestPointee>::result &&
		sizeof(SrcPointee) == sizeof(DestPointee) ? Fast : Conservative };

	return CopyImpl(first, last, result, Int2Type<useFast>);
}
//   (MyType)POD  
template <> struct SupportsBitwiseCopy < MyType >
{
	enum { result = true };
};