Narzędzia użytkownika

Narzędzia witryny


type_traits

/* * Autor: Piotr Buczkowski, 192902, N1-ISIII2 * * Temat: boost::type_traits * * Opis dotyczy biblioteki w wersji 1.38 * * Biblioteka „boost::type_traits” zawiera zbiór specyficznych klas cech, * z których każda obejmuje pojedynczą cechę systemu C++. * Na przykład czy dany typ jest wskaźnikiem czy referencją? * Lub czy typ posiada konstruktor domyślny albo kwalifikator „const”? * * Klas „type_traits” używamy ich w programowaniu generycznym * do określenia właściwości danego typu i optymalizacji * odpowiednich dla danego przypadku. * * Biblioteka „type_traits” zawiera także zbiór klas * dokonujących specyficznych transformacji na danym typie. * Potrafią na przykład usunąć kwalifikator „const” lub „volatile”. * Każda klasa dokonująca transformacji definiuje * wewnętrzny składnik „type” będący typem transformacji. * */


/* * Szablon „integral_constant” jest w hierarchii dziedziczenia * przodkiem klas „true_type” oraz „false_type” */ template <class T, T val> struct integral_constant {

typedef integral_constant<T, val> type;
typedef T value_type;
static const T value = val;

};

/* * Klasy „type_traits” mają wspólną cechę: * każda dziedziczy po „true_type” jeśli ma określoną właściwość * lub po „false_type” w przeciwnym wypadku. * Tak więc: * „true_type” jest typem oznaczającym, że klasa posiada daną cechę * „false_type” jest typem oznaczającym, że klasa danej cechy nie posiada */ typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type;

/* * Rozważmy najprostszą klasę w bibliotece: „is_void<T>”. * Dziedziczy ona po „true_type” tylko jeśli jako typ „T” podamy „void”. * Mówimy, że klasa szablonowa „is_void” dostarcza pełnej specjalizacji * (full-specialization), gdy typ „T” to „void”. Jest to dość ważna technika, * ale czasem potrzebujemy czegoś pomiędzy rozwiązaniem generycznym * a pełną specjalizacją. To dlatego komitet standaryzacyjny zdefiniował * częściową specjalizację (partial template-class specialization). */ template <typename T> struct is_void : public false_type{};

template <> struct is_void<void> : public true_type{};

/* * Kolejny przykład to klasa „is_pointer<T>”. * Głowna wersja obsługuje przypadki gdy „T” nie jest wskaźnikiem, * a częściowa specjalizacja w przeciwnym razie. */ template <typename T> struct is_pointer : public false_type{};

template <typename T> struct is_pointer<T*> : public true_type{};

/* * Generalnie obowiązuje zasada, że aby napisać częściową specjalizację * należy uprzednio napisać główną wersję. */

/* * Przyjrzyjmy się przykładowi pokazującemu sposób w jaki klasy cech mogą być użyte. * Pokazuje on w jaki sposób klasy cech mogą być użyte * do podjęcia decyzji o optymalizacji w czasie kompilacji. * Rozważmy algorytm kopiujący z biblioteki standardowej: */ template <typename Iter1, typename Iter2> Iter2 copy(Iter1 first, Iter1 last, Iter2 out); /* * W pewnych okolicznościach kopiowanie może być przeprowadzone najefektywniej * z użyciem funkcji „memcpy”, ale by tak uczynić spełnione muszą być następujące warunki: * - operator przypisania nie został zdefiniowany przez programistę * - brak składników będących referencjami * - wszystkie klasy bazowe oraz składniki klasy muszą mieć trywialny operator przypisania * * Biblioteka „type_traits” dostarcza klasę „has_trivial_assignment” taką, * że „has_trivial_assignment<T>::type” ma wartość „true” tylko wtedy, * gdy typ „T” ma trywialny operator przypisania. */ /* * Rozważmy następujący przykład: */ namespace detail {

/*
 * Szablon funkcji robiącej wolną, ale bezpieczną kopię.
 */
template<typename I1, typename I2, bool b>
I2 do_copy(I1 first, I1 last, I2 out, const integral_constant<bool, b>&)
{
   while(first != last)
   {
	  *out = *first;
	  ++out;
	  ++first;
   }
   return out;
}
/*
 * W tej wersji funkcji kopiującej wymagamy,
 * aby oba iteratory wskazywały na ten sam typ
 * oraz by ostatni parametr był typu "true_type".
 */
template<typename T>
T* do_copy(const T* first, const T* last, T* out, const true_type&)
{
   memcpy(out, first, (last-first)*sizeof(T));
   return out+(last-first);
}

}

/* * W tej wersji funkcji kopiującej posługujemy się funkcją „do_copy” * przekazując jej informację o typie wartości wskazywanych * przy użyciu „has_trivial_assign<value_type>”. * Spowoduje to wybranie wersji funkcji „do_copy” z „memcpy” * tylko tam gdzie tego chcemy * (czyli jedynie dla typów posiadających trywialny operator przypisania) * lub wersji wolniejszej lecz bezpiecznej w przeciwnym przypadku. */ template<typename I1, typename I2> inline I2 copy(I1 first, I1 last, I2 out) {

 /*
  * Kopiujemy przy użyciu "memcpy" jeżeli "T" ma trywialny operator przypisania
* oraz jeśli argumentami są wskaźniki.
  */
 typedef typename std::iterator_traits<I1>::value_type value_type;
 return detail::copy_imp(first, last, out, boost::has_trivial_assign<value_type>());

}

/* * W następnym przykładzie rozważmy prostą parę dwóch typów: */ template <typename T1, typename T2> struct pair {

T1 first;
T2 second;
/*
 * Ta prosta para nie może przechowywać referencji,
 * gdyż konstruktor musiałby przyjmować wtedy referencje do referencji.
 */
pair(const T1& nfirst, const T2& nsecond) : first(nfirst), second(nsecond) {}

}; /* * Aby zaradzić powyższemu problemowi posłużymy się klasą „add_reference”, * która dodaje referencję do typu nie-referencyjnego. */ #include <boost/type_traits/add_reference.hpp> template <typename T1, typename T2> struct improved_pair {

T1 first;
T2 second;
improved_pair(boost::add_reference<const T1>::type nfirst,
	boost::add_reference<const T2>::type nsecond) :
		first(nfirst), second(nsecond) {}

};

/* * Powyższe przykłady demonstrowały ideę klas cech * oraz to w jaki sposób mogą one zostać użyte. * Kompletnej listy dostępnych klas należy szukać w dokumentacji „boost”. */

type_traits.txt · ostatnio zmienione: 2009/04/30 07:11 przez pbuczko1