<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Блоги &#187; Malyshev Egor</title>
	<atom:link href="http://software.intel.com/ru-ru/blogs/author/malyshev-egor/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/ru-ru/blogs</link>
	<description></description>
	<lastBuildDate>Thu, 24 May 2012 12:16:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>C/C++ like Java</title>
		<link>http://software.intel.com/ru-ru/blogs/2012/05/15/cc-like-java/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2012/05/15/cc-like-java/#comments</comments>
		<pubDate>Tue, 15 May 2012 06:10:51 +0000</pubDate>
		<dc:creator>Malyshev Egor</dc:creator>
				<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Acceler8]]></category>
		<category><![CDATA[accelerate 2012]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Си++]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2012/05/15/cc-like-java/</guid>
		<description><![CDATA[Привет всем! Сегодня мы с вами поговорим о любви C/C++ к Java. Связь не очевидна, но она есть. Итак, поехали! В прошлый раз мы с вами говорили об обратной задаче, а стоило ли когда-нибудь выполнять эту? Очевидно, что и такое нам тоже нужно, когда например нашему методу передаётся объект, который предоставляет нам какие-то услуги, которые [...]]]></description>
			<content:encoded><![CDATA[<p>Привет всем!</p>
<p>Сегодня мы с вами поговорим о любви C/C++ к Java. Связь не очевидна, но она есть. Итак, поехали! <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><a href="http://software.intel.com/ru-ru/blogs/2012/05/12/java-like-c/">В прошлый раз</a> мы с вами говорили об обратной задаче, а стоило ли когда-нибудь выполнять эту?</p>
<p>Очевидно, что и такое нам тоже нужно, когда например нашему методу передаётся объект, который предоставляет нам какие-то услуги, которые мы в свою очередь должны выполнить. Ну или опять банальный пример, нам попросту нужно вызывать выполнять некоторые задачи из другого проекта в среде своего проекта.</p>
<p>Рассмотрим опять что-нибудь незамысловатое, чтобы не пудрить сильно мозги. <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Допустим, у нас есть Java класс, в котором реализован метод, который приветствует другой объект.  Вот как выглядит класс с методом:</p>
<pre name="code" class="java">public class Hello {
      public static int HelloObject(PeopleObject people)  {
	    System.out.println("Height" + people.height);
	    System.out.println("Name:" + people.name);
	    System.out.println("Town:" + people.town);
	    System.out.println("Age:" + people.age);
	    return OK;
	}
}</pre>
<p>Вот как выглядит сам класс:</p>
<pre name="code" class="java">public class PeopleObject {
	public int height;
	public String name;
	public String town;
	public int age;
	public PeopleObject(int height, String name, String town, int age) {
		this.height = height;
		this.name = name;
		this.town = town;
		this.age = age;
	}
}</pre>
<p>Со стороны Java всё готово, теперь подготовим площадку в C/C++, для вызова нашего метода.</p>
<p>Для того что бы вызвать наш метод  из C/C++, вначале нам понадобится загрузить (создать) JVM (виртуальную Java машину) используя следующее:</p>
<pre name="code" class="cpp">JNIEnv * loadJVM(JavaVM ** jvm) {
    JavaVMOption jvmOptions;
    jvmOptions.optionString = "-Djava.class.path=C:\\JavaClassFiles";
    JavaVMInitArgs jvmArgs;
    jvmArgs.version = JNI_VERSION_1_6;
    jvmArgs.nOptions = 1;
    jvmArgs.options = &#038;jvmOptions;
    jvmArgs.ignoreUnrecognized = JNI_TRUE;
    JNIEnv * env;
    int OK = JNI_CreateJavaVM(jvm, (void**)&#038;env, &#038;jvmArgs);
    if(OK < 0) printf("\nUnable to Launch JVM\n");
    return env;
}</pre>
<p>Итак, по порядку:<br />
<code>jvmOptions.optionString = "-Djava.class.path=C:\\JavaClassFiles";</code><br />
в этой строке мы указываем папку исходников, где располагаются файлы классов. Далее <code>jvmArgs</code> описывает аргументы для вызова Java машины. </p>
<pre name="code" class="cpp">jvmArgs.version = JNI_VERSION_1_6;
jvmArgs.nOptions = 1;
jvmArgs.options = &amp;jvmOptions;
jvmArgs.ignoreUnrecognized = JNI_TRUE;</pre>
<p>в первой строчке мы задаём версию Java, во второй мы задаём кол-во опций, так как они хранятся в массиве, в данном случае мы задаём опцию для Java машины, и в четвёртой строке мы указываем игнорировать все нераспознанные опции, строка которых начинается с "-X" or "_" (Не обязательно).</p>
<p>Теперь вызовем создание Java машины:</p>
<pre name="code" class="cpp">JNIEnv *env;
JavaVM * jvm;
env = loadJVM(&#038;jvm);
if (env == NULL) return BAD;</pre>
<p>А теперь всё готово для начала работы с Java методами, объектами. Для начала найдём два наших класса:</p>
<pre name="code" class="cpp">jclass clsH = env->FindClass("Hello");
jclass clsP = env->FindClass("PeopleObject");</pre>
<p>Метод “FindClass” ищет класс по имени.</p>
<p>Теперь у класса “Hello”, получим метод “HelloObject”.</p>
<pre name="code" class="cpp">jmethodID midHelloObject = NULL;
if (clsH != NULL)  {
	midHelloObject = env->GetStaticMethodID(clsH,"HelloObject","(LPeopleObject;)I");
} else {
    	printf("\nUnable to find the requested class\n");
}</pre>
<p>Тут тоже всё довольно понятно, по сути, мы просто работаем со всеми методами, только через сторонний интерфейс.</p>
<p>Метод <code>GetStaticMethodID</code> ищет метод в классе <code>clsH</code> с именем <code>HelloObject</code> и нужной сигнатурой. О том как генерировать сигнатуру не ручками, скажем позже.</p>
<p>Теперь получим конструктор класса “PeopleObject”, для того, чтобы в него передать нужные параметры для создания объекта.</p>
<pre name="code" class="cpp">jmethodID midPeopleObjectConst = NULL;
if(clsP != NULL)  	{
	midPeopleObjectConst = env->GetMethodID(clsP, "&lt;init&gt;", "(ILjava/lang/String;Ljava/lang/String;I)V");
} else  {
	printf("\nUnable to find the requested class\n");
}</pre>
<p>Словом <code>"&lt;init&gt;"</code> мы показываем, что это будет именно конструктор.<br />
Ну а теперь сделаем то, что задумали:</p>
<pre name="code" class="cpp">jobject jobjPeople = NULL;
if (midHelloObject!=NULL)  {
	if(clsP != NULL &#038;& midHelloObjectConst != NULL)  {
		char  cName[255] = “Yuki”;
		jstring name = env->NewStringUTF(cName);
		char  cTown[255] = “Tokyo”;
		jstring town = env->NewStringUTF(cTown);
		int cHeight = 169;
		jint height = (jint) cHeight;
		int cAge = 17;
		jint age = (jint) cAge;
		jobjPeople = env->NewObject(clsP, midPeopleObjectConst, height, name, town,  age);
	}
	if(jobjPeople != NULL &#038;& midHelloObject!= NULL)
		env->CallStaticIntMethod(clsH,midHelloObject,jobjPeople);
}</pre>
<p>Что тут происходит? Да всё то же самое, подготавливаются параметры для создания объекта <code>PeopleObject</code>. Далее создаётся объект класса <code>PeopleObject</code> через его конструктор. А дальше вызывается метод из класса <code>Hello</code>, с передачей в функцию <code>HelloObject</code>, объекта класса <code>PeopleObject</code>.</p>
<p>Ну и в конце не забываем уничтожить Java машину: <code>jvm-&gt;DestroyJavaVM();</code></p>
<p>Вот и всё <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Ах, да, как же генерировать правильно сигнатуру? Это можно делать и руками, но можно легко ошибиться, да и очень много работы. Генерировать сигнатуры можно при помощи утилиты “javap”, входящей в состав JDK. Например, если запустить её для класса “Hello” (<code>javap -s -p Hello</code>), то мы получим:</p>
<pre name="code" class="cpp">//Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello ();
  	Signature: ()V
public static void main(java.lang.String[]);
  	Signature: ([Ljava/lang/String;)V
public static int HelloObject(PeopleObject);
  	Signature: (LPeopleObject;)I
}</pre>
<p>Cкажу напоследок, что если у вас 64-битная архитектура, то у вас возможно возникнут проблемы с компиляцией и запуском приложения. Дело в том что JDK 64-bit поставляет не совсем пригодные для таких операций библиотеки, поэтому лучше скачать JDK 32-bit и подключать либы оттуда.</p>
<p>Теперь мы показали взаимную любовь Java &amp; C/C++, и можно за них порадоваться <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /><br />
Подробнее обо всё можно почитать по-прежнему на сайте Oracle.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2012/05/15/cc-like-java/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java like С/C++</title>
		<link>http://software.intel.com/ru-ru/blogs/2012/05/12/java-like-c/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2012/05/12/java-like-c/#comments</comments>
		<pubDate>Sat, 12 May 2012 09:14:17 +0000</pubDate>
		<dc:creator>Malyshev Egor</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Acceler8]]></category>
		<category><![CDATA[Accelerate]]></category>
		<category><![CDATA[accelerate 2012]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JNI]]></category>
		<category><![CDATA[Си++]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2012/05/12/java-like-c/</guid>
		<description><![CDATA[Привет всем! Сегодня мы с вами поговорим о любви Java к C++. Связь не очевидна, но она есть. Итак, поехали! Порой в нашей жизни требуется использовать код, написанный на другом языке. Опишем несколько случаев такой необходимости: Пускай у вас есть проверенный на 100% код на другом языке. Для того что бы его перевести на язык [...]]]></description>
			<content:encoded><![CDATA[<p>Привет всем!</p>
<p>Сегодня мы с вами поговорим о любви Java к C++. Связь не очевидна, но она есть. Итак, поехали!</p>
<p>Порой в нашей жизни требуется использовать код, написанный на другом языке. Опишем несколько случаев такой необходимости:</p>
<ul>
<li>Пускай у вас есть проверенный на 100% код на другом языке. Для того что бы его перевести на язык Java, потребуется немало времени, а полученный код нужно опять проверять и отлаживать. Особенно если это огромная библиотека или проект.</li>
<li>Или нам нужны низкоуровневые операции для доступа к аппаратным средствам, в таком случае Java не очень подходит для таких операций. </li>
<li>Или если нам нужно множественное применение сложных операций с машиной, требующих очень оптимизированного кода, чего на Java опять не добьёшься (хотя этому можно поставить в противовес just-in-time компиляцию). </li>
</ul>
<p>Если мы всё же столкнулись с одной из вышеперечисленных проблем, то, скорее всего нам-таки придётся научиться вызывать платформенно-ориентированный код прямиком из Java. Для этого в Java предусмотрены специальные способы работы с системными библиотеками, а JDK содержит инструменты, которые позволят нам справиться с этими проблемами.</p>
<p>Конечно, всё это не избавляет нас от полноценного решения, так как для каждой операционной системы потребуются библиотеки, ориентированные именно на эту среду, и хоть и Java очень хорошо контролируемый язык, то C++ в свою очередь неконтролируем, поэтому возможно, что методы из C++ выведут из строя виртуальную Java-машину, либо вызовет сбой системы или ещё что-нибудь.</p>
<p>Но выбор за вами, стоит ли это делать в ситуации, с которой вы столкнулись или нет <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Я не буду описывать кучу методов, кучу ситуаций, и тому подобное, это лучше всего расскажет специализированная книжка, а тут будет приведены примеры почти стандартных задач, вида Hello “damn” world! <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Итак, наша задача: на языке C/C++ есть функция, которая выполняет какие-то сумасшедше-полезные действия. И мы хотим её вызвать из Java (да-да, нам лень переписать её на Java <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ). Пускай это функция вывода printf (можно использовать и другие, но будем ориентироваться на C), которая приветствует передаваемую строку и какое-то число.</p>
<p>Для того, чтобы в Java показать, что функция будет платформенно-ориентированной, есть ключевое слово “<strong>native</strong>”, которое предупреждает компилятор о внешнем определении данного метода.  Саму функцию нужно описывать в классе.</p>
<pre name="code" class="java">public static native void welcome(String str, int value);</pre>
<p>В данном случае функция объявлена как статическая, но это не обязательное условие. Теперь поместим её в класс:</p>
<pre name="code" class="java">class Hello {
      public static native void welcome(String str, int value);
}</pre>
<p>Такой класс откомпилировать вы сможете, но вылетит исключение, говорящее, что программа не может найти метод. Для того? чтобы метод был найден, его тело нужно создать на C/C++, причём не просто метод, а метод говорящий что его будут вызывать из кода на Java. Но об этом попозже, просто знайте, что мы создадим разделяемую библиотеку для экспорта на C/C++, а далее загрузим её в Java. И только тогда программа найдёт этот метод и сможет успешно выполняться.</p>
<p>Библиотеку удобнее всего подключить в статическом блоке, чтобы при вызове функции, она уже была подгружена. И вот что получается:</p>
<pre name="code" class="java">class Hello {
   public static native void welcome(String str, int value);
   static  {
      System.loadLibrary("JAVALOVECHELLO");
   }
}</pre>
<p>Метод <code>loadLibrary("JAVALOVECHELLO")</code>, загружает библиотеку по имени <code>JAVALOVECHELLO</code>. </p>
<p>Теперь настало время для создания C/C++ функции, имя которой должно строго (значит точно) соответствовать соглашениям об именовании:</p>
<ul>
<li> Имя метода в C/C++ должно полностью соответствовать ПОЛНОМУ имени в Java программе. Например, если мы поместим программу в пакет com.intel, тогда полное имя Java-метода будет com.intel.Hello.welcome. Теперь нужно заменить все точки на нижние подчёркивания (_) и добавить префикс “Java_”, получим строку <code>Java_com_intel_Hello_welcome</code>. Если код находится в пакете “default”, то имя C-функции должно выглядеть так: <code>Java_Hello_welcome</code>. </li>
<li>Стоит быть внимательными с различными Unicode-символами: их нужно заменять на их 16-ричное представление, но об этом не будем тут. На самом деле и это ещё не все соглашения, но сейчас расскажем, как не делать этого ручками.</li>
</ul>
<p>Для правильно описанных методов не стоит их создавать руками, для этого воспользуемся специальной утилитой “<strong>javah</strong>”, которая есть в JDK. Для начала откомпилируем наш Java-файл, используя “<strong>javac</strong>”.</p>
<p><code>javac Hello.java</code></p>
<p>Теперь воспользуемся “javah”.</p>
<p><code>javah Hello</code></p>
<p>В результате выполнения этих операций мы получим файл “Hello.h”</p>
<pre name="code" class="cpp">
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class Hello */
#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Hello
 * Method:    welcome
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Hello_welcome
  (JNIEnv *, jclass, jstring, jint);
#ifdef __cplusplus
}
#endif
#endif</pre>
<p>Как видно, так как мы пишем на C++, то добавлена строчка <code>extern "C"</code>, которая об этом сообщает. Имена <code>JNIEXPORT</code> и <code>JNICALL</code> описаны в <code>jni.h</code>, они задают спецификаторы функций, экспортируемых из динамических библиотек .</p>
<p>В данном файле всё довольно понятно, всё как мы и предполагали (на самом деле не всё, но об этом позже).</p>
<p>Осталось для данного файла заголовка написать соответствующий файл c исходным кодом, где мы и опишем тело метода.</p>
<p>Вот как он будет выглядеть:</p>
<pre name="code" class="cpp">
#include "Hello.h"
#include
JNIEXPORT void JNICALL Java_Hello_welcome(JNIEnv* env, jclass cl, jstring str, jint value)
{
   const char * ccstr;
   ccstr = (*env).GetStringUTFChars(str, NULL);
   printf("Hello damn World, %s, %d!\n", ccstr, (int)value);
}
</pre>
<p>Во всех вызовах JNI-функций есть указатель <code>env</code>, который является первым параметром любого платформенно-ориентированного метода. Параметр <code>env</code> указывает на таблицу функций, содержащую указатели функций. </p>
<p>Как наверно можно догадаться <code>jstring</code>, <code>jint</code> это по сути те же <code>string</code>, <code>int</code>, но только в понимании JNI (их соответствия).</p>
<p>Функция <code>GetStringUTFChars()</code> возвращает указатель <code>const jbyte *</code> на символы строки, представленные в формате UTF-8. Также не помешает после использования строк освобождать память. Если же этого не делать, то это может повлиять на работу метода (память не безгранична). Для этих целей нужно использовать метод <code>ReleaseStringUTFChars()</code>.</p>
<p>Очень подробное описание всех функций (API JNI) можно найти сайте Oracle, по этой ссылке - <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html">http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html</a>.</p>
<p>Как компилировать динамическую библиотеку каждый выбирает сам, это можно сделать вручную, или можно предоставить всё MVS.</p>
<p>Нужные вам библиотеки, необходимые для успешной компиляции C/C++, лежат в <strong>JDK/include</strong>.</p>
<p>Ну и осталось написать вызов функции из Java-программы:</p>
<pre name="code" class="java">
class HelloTest {
   public static void main(String[] args)    {
      Hello.welcome("I'm a string", 100500);
   }
}
</pre>
<p>На этом закончим, хоть и было рассмотрено материала 7% от общего, но тут главное смысл, а дальше уже как по маслу, берёшь и намазываешь <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2012/05/12/java-like-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Списки типов и не только. Часть Infinity.</title>
		<link>http://software.intel.com/ru-ru/blogs/2011/11/24/infinity-2/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2011/11/24/infinity-2/#comments</comments>
		<pubDate>Thu, 24 Nov 2011 14:09:22 +0000</pubDate>
		<dc:creator>Malyshev Egor</dc:creator>
				<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Acceler8]]></category>
		<category><![CDATA[compiler]]></category>
		<category><![CDATA[precompiled]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[typeoflist]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2011/11/24/infinity-2/</guid>
		<description><![CDATA[<p>Все уже много наслышаны, а может и не все, об этой изъезженной теме, но всё таки повторимся, только в более крупных масштабах, и неформальной обстановке.</p>

<p>Много ли ваших программ выполняет свою работу, и считает ответ уже на этапе компиляции? Сегодня я в минимуме описания и массе примеров, покажу как и что работает.</p>
]]></description>
			<content:encoded><![CDATA[<p>Все уже много наслышаны, а может и не все, об этой изъезженной теме, но всё таки повторимся, только в более крупных масштабах, и неформальной обстановке.</p>
<p>Много ли ваших программ выполняет свою работу, и считает ответ уже на этапе компиляции? Сегодня я в минимуме описания и массе примеров, покажу как и что работает.</p>
<p>Сразу скажу, кто знаком с темой может дальше не читать. Эта тема, да и не только она, очень очень глубоко рассматривается в книге Александреску в «Современное проектирование на С++». Лично я её сам почти не читал, но в плане пошевелить левой и правой долей мозга она поможет, может запутать, а может и распутать что-нибудь этакое! Поехали!</p>
<p>Итак, списки типов... предоставляют собой средство для манипулирования коллекциями типов.</p>
<p>Начнём с простейшего, и постепенно будем увеличиваться.</p>
<h2>Просто список</h2>
<p>Определим список типов, его общий вид:</p>
<pre name="code" class="cpp">
template&lt;typename T, typename U&gt;
struct TypeList
{
    T Head;		//Голова
    U Tail;		//Хвост
};
</pre>
<p>Те, кто знаком с шаблонами, знают, что теперь мы можем передавать любые типы в список, это и будут наши типы.<br />
В данном определении видно, что у нас хвост и голова это два неких типа.</p>
<p>Пусть голова определяет тот тип, который сейчас стоит вначале, а хвост определяет список, идущий после головы, т.е в хвосте, будет своя голова и свой хвост, и т.д.. Но нужно как то признак конца. Для этого мы создадим пустой список (аналог NULL), который и будет сообщать, что список закончился.</p>
<p>Итак, определим ещё некоторые вещи.</p>
<p>Создание списка из трёх разных типов:</p>
<pre name="code" class="cpp">
typedef TypeList&lt;int, TypeList&lt;double, char&gt; &gt; someTypeList;
</pre>
<p>Теперь пустой список:</p>
<pre name="code" class="cpp">
struct NullType {};
</pre>
<p>Описание списка из одного элемента:</p>
<pre name="code" class="cpp">
typedef TypeList&lt;int, NullType&gt; onlyType;
</pre>
<p>Вы заметили, что описание списка из 7 элементов будет довольно некомпактным? Не беда, в с++ есть #define!<br />
И вот как мы поступим. Вначале список длины 1:</p>
<pre name="code" class="cpp">
#define TYPELIST_1(T01)	TypeList&lt;T01, NullType&gt;
</pre>
<p>Теперь длины 2:</p>
<pre name="code" class="cpp">
#define TYPELIST_2(T01, T02) TypeList&lt;T01, TYPELIST_1(T02) &gt;
</pre>
<p>Понятно, да?</p>
<pre name="code" class="cpp">
#define TYPELIST_1(T01)	TypeList&lt;T01, NullType&gt;
#define TYPELIST_2(T01, T02) TypeList&lt;T01, TYPELIST_1(T02) &gt;
#define TYPELIST_3(T01, T02, T03) TypeList&lt;T01, TYPELIST_2(T02, T03) &gt;
#define TYPELIST_4(T01, T02, T03, T04) TypeList&lt;T01, TYPELIST_3(T02, T03, T04) &gt;
#define TYPELIST_5(T01, T02, T03, T04, T05) TypeList&lt;T01, TYPELIST_4(T02, T03, T04, T05) &gt;
#define TYPELIST_6(T01, T02, T03, T04, T05, T06) TypeList&lt;T01, TYPELIST_5(T02, T03, T04, T05, T06) &gt;
#define TYPELIST_7(T01, T02, T03, T04, T05, T06, T07) TypeList&lt;T01, TYPELIST_6(T02, T03, T04, T05, T06, T07) &gt;
</pre>
<p>Теперь создадим список из трёх элементов:</p>
<pre name="code" class="cpp">
typedef TYPELIST_3(int, double, float) someTypeList;
</pre>
<p>Ну вот, стало попроще.</p>
<p>Итак, пора бы придумать кучу задач на списки типов (думаете это нереально? <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ), и сделать так, что бы всё это отрабатывало во время компиляции с хорошей скоростью.</p>
<p>Дальше пойдут различные условия, что нужно сделать со списком типов, и решение, придуманное на ходу (так оно и было!), и описанное, так сказать, в свободной форме. Поехали!</p>
<p>Как же с коллекцией чего-то, да без длины! Непорядок!</p>
<h2>Длина списка</h2>
<pre name="code" class="cpp">
template&lt;class TList&gt;
struct Length;

template&lt;&gt;
struct Length<NullType>
{
    enum { value = 0 };
};

template&lt;typename Head, typename Tail&gt;
struct Length&lt;TypeList&lt;Head, Tail&gt; &gt;
{
    enum {value = 1 + Length&lt;Tail&gt;::value };
};
</pre>
<p>Длина нулевого списка типов равна 0.<br />
Длина любого другого списка типов равна 1 плюс длина его оставшейся части.<br />
Но в итоге получаем, на этапе компиляции, статическую константу, равную длине списка типов</p>
<pre name="code" class="cpp">
enum {value = 1 + Length&lt;Tail&gt;::value };
</pre>
<p>Тут мы хитрим, используя тип перечисления enum, int и прочие типы тут использовать нельзя, так же забудьте про if, и остальное, но не забывайте про конструкцию вида (ok) ? A : B;</p>
<pre name="code" class="cpp">
template&lt;typename Head, typename Tail&gt;
struct Length&lt;TypeList&lt;Head, Tail&gt; &gt;
{
    enum {value = 1 + Length&#038;ltTail&#038;gt::value };
};
</pre>
<p>Вот это общий метод вычисления длины, когда ещё есть и начало, и хвост, поступаем, как описано, было выше.</p>
<pre name="code" class="cpp">
template&lt;&gt;
struct Length&lt;NullType&gt;
{
    enum { value = 0 };
};
</pre>
<p>Тут уже идёт специализация, ибо мы хотим заходить сюда, только в случае, если список стал пустым (помните NullType), ну и понятно, что его длина равна 0.</p>
<pre name="code" class="cpp">
template&lt;class TList&gt;
struct Length;
</pre>
<p>А это общее описание, без тела.</p>
<p>Всё остальные задачки, будут выглядеть примерно так же, общий метод, специализации и общее описание.</p>
<p>Ну и покажем, как же теперь вычислить длину списка:</p>
<pre name="code" class="cpp">
int x = Length&lt; TYPELIST_3(int, double, string) &gt;::value;
cout &gt;&gt; x &gt;&gt; endl;
</pre>
<p>Отлично, вот и первая задачка решена!</p>
<h2>Индексированный доступ:</h2>
<p>Если индекс i больше чем кол-во элементов в списке, то возвращается тип по умолчанию, иначе возвращается тип, стоящий на позиции i в списке.<br />
Как только i стало равно 0, значит, что мы дошли до нужного типа, возвращаем Head, иначе, если i станет отрицательным, т.е. не подойдёт ни под одну специализацию, возвратится тип по умолчанию, в общем случае, мы уменьшаем i и двигаемся вправо по списку.</p>
<pre name="code" class="cpp">
template&lt;typename TList, std::size_t i, typename DefT = NullType&gt;
struct TypeAt
{
    typedef DefT Result;
};

template&lt;typename Head, typename Tail, typename DefT&gt;
struct TypeAt&lt;TypeList&lt;Head, Tail&gt;, 0, DefT&gt;
{
    typedef Head Result;
};

template&lt;typename Head, typename Tail, std::size_t i, typename DefT&gt;
struct TypeAt&lt;TypeList&lt;Head, Tail&gt;, i, DefT&gt;
{
    typedef typename TypeAt&lt;Tail, i - 1, DefT&gt;::Result Result;
};
</pre>
<p>Использование:</p>
<pre name="code" class="cpp">
TypeAt&lt;TYPELIST_3(int, char, string), 1&gt;::Result someTypeA;
TypeAt&lt;TYPELIST_3(int, double, string), 5, int&gt;::Result someTypeB;
cout &lt;&lt; someTypeA &lt;&lt; endl; // char
cout &lt;&lt; someTypeB &lt;&lt; endl; // int
</pre>
<h2>Вычисление индекса типа в списке.</h2>
<p>Бежим по списку, если список стал пустым, то значит тип не найден, возвращаем -1. Если мы встали на нужный нам тип, то начинаем считать какой же это номер, начиная с него. Поэтому value = 0, так как мы бежим назад теперь, это ведь как рекурсия и прибавляем по +1, если же у нас получился -1, то операция +1, будет -1 оставлять -1, что бы в итоге получилось -1 и стало понятно, что ничего не найдено.</p>
<pre name="code" class="cpp">
template&lt;typename TList, typename T&gt;
struct IndexOf;

template&lt;typename T&gt;
struct IndexOf&lt;NullType, T&gt;
{
    enum { value = -1 };
};

template&lt;typename T, typename Tail&gt;
struct IndexOf&lt;TypeList&lt;T, Tail&gt;, T&gt;
{
    enum { value = 0 };
};

template&lt;typename Head, typename Tail, typename T&gt;
struct IndexOf&lt;TypeList&lt;Head, Tail&gt;, T&gt;
{
private:
    enum { temp = IndexOf&lt;Tail, T&gt;::value };
public:
    enum { value = ((temp == -1) ? -1 : 1 + temp) };
};
</pre>
<p>Применение:</p>
<pre name="code" class="cpp">
int y = IndexOf&lt;TYPELIST_3(int, double, string), double&gt;::value;
int z = IndexOf&lt;TYPELIST_3(int, double, string), float&gt;::value;
cout &lt;&lt; y &gt;&gt; endl; // 1
cout &lt;&lt; z &gt;&gt; endl; // -1
</pre>
<h2>Наверно уже пора всё таки узнавать, а что же мы получаем?</h2>
<p>Для этого мы хотим распечатать наш список, да без проблем!</p>
<pre name="code" class="cpp">
template &lt;typename T&gt;
void FPrint()
{
    cout &lt;&lt; typeid(T).name() &lt;&lt; endl;
}

template &lt;typename TList&gt; struct KPrint;

template &lt;typename Head, typename Tail&gt;
struct KPrint&lt;TypeList&lt;Head, Tail&gt; &gt;
{
    static void Print()
    {
        FPrint&lt;Head&gt;();
        KPrint&lt;Tail&gt;::Print();
    }
};

template &lt;&gt;
struct KPrint&lt;NullType&gt;
{
    static void Print()
    {
        cout &lt;&lt; "==== End of list ====nn";
    }
};
</pre>
<p>Тут всё просто, бежим по порядку, и каждый элемент выводим на печать.</p>
<pre name="code" class="cpp">
KPrint&lt;TYPELIST_3(int, char, byte)&gt;::Print(); // int char byte
</pre>
<p>А теперь начнём массовое уничтожение мозга!</p>
<h2>Соединение двух списков в один</h2>
<p>Второй дописывается в конец:<br />
Если первый список пустой, а второй является списком, то их объединение это и есть второй список.<br />
Если первый список пустой, а второй является элементом (т.е 1 типов), то их объединение это список из 1 типа.<br />
Если первый список не пустой, то их объединение это голова первого списка + объединение хвоста со вторым списком.</p>
<pre name="code" class="cpp">
template&lt;typename TListA, typename TListB&gt;
struct Append;

template&lt;&gt;
struct Append&lt;NullType, NullType&gt;
{
    typedef NullType Result;
};

template &lt;typename T&gt;
struct Append&lt;NullType, T&gt;
{
    typedef TypeList&lt;T, NullType&gt; Result;
};

template&lt;typename Head&gt;
struct Append&lt;NullType, TypeList&lt;Head, NullType&gt; &gt;
{
    typedef TypeList&lt;Head, NullType&gt; Result;
};

template&lt;typename Head, typename Tail, typename T&gt;
struct Append&lt;TypeList&lt;Head, Tail&gt;, T &gt;
{
    typedef TypeList&lt;Head, typename Append&lt;Tail, T&gt;::Result &gt; Result;
};

template&lt;typename Head, typename Tail&gt;
struct Append&lt;NullType, TypeList&lt;Head, Tail&gt; &gt;
{
    typedef TypeList&lt; Head, Tail &gt; Result;
};
</pre>
<p>Использование:</p>
<pre name="code" class="cpp">
typedef Append< TYPELIST_3(int, double, long double), TYPELIST_3(float, char, short) >::Result typeAppend;
// int, double, long double, float, char, short
</pre>
<h2>Замена всех типов стоящих на чётных/нечётных местах, на другой тип.</h2>
<p>Тут мы поступим элегантным способом, заведем дополнительный параметр, который принимает значения 0 или 1, если параметр равен 1, то значит, текущий элемент нужно заменить, и переходим дальше с параметром 0, иначе если 0 то заменять не нужно, и переходим с состоянием 1. И если запустить с параметром 0, то меняться начнут 1, 3, ..., иначе 0, 2, ... Так же параметр по умолчанию равен 0, поэтому можно 0 и не передавать.</p>
<pre name="code" class="cpp">

template&lt;typename TList, typename U, std::size_t index = 0&gt;
struct ReplaceEvenOdd {
    typedef TList Result;
};

template&lt;typename U&gt;
struct ReplaceEvenOdd&lt;NullType, U&gt;
{
    typedef NullType Result;
};

template &lt;typename Head, typename Tail, typename U&gt;
struct ReplaceEvenOdd&lt;TypeList&lt;Head, Tail&gt;, U, 1&gt;
{
    typedef TypeList&lt;U, typename ReplaceEvenOdd&lt;Tail, U, 0&gt;::Result&gt; Result;
};

template &lt;typename Head, typename Tail, typename U&gt;
struct ReplaceEvenOdd&lt;TypeList&lt;Head, Tail&gt;, U, 0&gt;
{
    typedef TypeList&lt;Head, typename ReplaceEvenOdd&lt;Tail, U, 1&gt;::Result&gt; Result;
}; 
</pre>
<p>Применение:</p>
<pre name="code" class="cpp">
typedef ReplaceEvenOdd&lt;TYPELIST_5(int, char, double, short, float), long long&gt;::Result typeReplaceEven;
typedef ReplaceEvenOdd&lt;TYPELIST_5(int, char, double, short, float), long long, 1&gt;::Result typeReplaceOdd;
</pre>
<h2>Удаляем первый найденный тип, совпадающий с заданным.</h2>
<p>Бежим пока не встретим наш заданный тип, если в итоге не встретили, то ничего и не изменится, иначе возвращается остаток списка без головы.</p>
<pre name="code" class="cpp">

template &lt;class TList, class T&gt;
struct EraseFirst;

template &lt;class T&gt;
struct EraseFirst&lt;NullType, T&gt;
{
    typedef NullType Result;
};

template &lt;class T, class Tail&gt;
struct EraseFirst&lt;TypeList&lt;T, Tail&gt;, T&gt;
{
    typedef Tail Result;
};

template &lt;class Head, class Tail, class T&gt;
struct EraseFirst&lt;TypeList&lt;Head, Tail&gt;, T&gt;
{
    typedef TypeList&lt;Head, typename EraseFirst&lt;Tail, T&gt;::Result&gt; Result;
};
</pre>
<p>Применение:</p>
<pre name="code" class="cpp">
typedef EraseFirst&lt;TYPELIST_4(int, double, char, double), double&gt;::Result typeEraseFirst;
</pre>
<h2>Удаляем все типы, совпадающие с заданным.</h2>
<p>Задача почти такая же, как и предыдущая, только когда мы обнаруживаем наш тип, мы не возвращаем хвост без головы, а возвращаем то, что останется от головы после удаления в ней всех типов совпадающих с заданным.</p>
<pre name="code" class="cpp">
template &lt;class TList, class T&gt;
struct EraseAll;

template &lt;class T&gt;
struct EraseAll&lt;NullType, T&gt;
{
    typedef NullType Result;
};

template &lt;class T, class Tail&gt;
struct EraseAll&lt;TypeList&lt;T, Tail&gt;, T&gt;
{
    typedef typename EraseAll&lt;Tail, T&gt;::Result Result;
};

template &lt;class Head, class Tail, class T&gt;
struct EraseAll&lt;TypeList&lt;Head, Tail&gt;, T&gt;
{
    typedef TypeList&lt;Head, typename EraseAll&lt;Tail, T&gt;::Result&gt; Result;
};
</pre>
<p>Применение:</p>
<pre name="code" class="cpp">
typedef EraseAll&lt;TYPELIST_5(int, double, char, double, short), double&gt;::Result typeEraseAll;
</pre>
<h2>Удаляем все дубликаты типов.</h2>
<p>Тут всё интересней. Допустим мы, сейчас имеем список, тогда отщепим от него голову, удалим все дубликаты в хвосте, а теперь в том, что получилось, удалим первый тип, совпадающий с головой, и присоединим все, что осталось к голове. Это и будет ответом для текущего списка. Ну, смотрите, раз мы удалили все дубликаты в хвосте, то понятное дело все типы там встречаются по 1 разу, значит если там есть голова, то она тоже встречается 1 раз, когда мы запустим удаление головы, она станет встречаться там 0 раз, следовательно присоединив это всё к голове, у нас не будет дубликатов!</p>
<pre name="code" class="cpp">
template &lt;class TList&gt;
struct EraseDuplicates;

template &lt;&gt;
struct EraseDuplicates&lt;NullType&gt;
{
    typedef NullType Result;
};

template &lt;class Head, class Tail&gt;
struct EraseDuplicates&lt;TypeList&lt;Head, Tail&gt;&gt;
{
    private:
        typedef typename EraseDuplicates&lt;Tail&gt;::Result L1;
        typedef typename EraseFirst&lt;L1, Head&gt;::Result L2;

    public:
        typedef TypeList&lt;Head, L2&gt; Result;
};
</pre>
<p>Применение:</p>
<pre name="code" class="cpp">
typedef EraseDuplicates&lt; TYPELIST_7(int, double, char, double, int, char, char)&gt;::Result typeEraseDuplicates; // int double char
</pre>
<p>Напоминаю, что это всё работает ещё на этапе компиляции. Ощущение что до сюда мало кто дошёл, но моё дело писать, писать, писать! Поехали дальше! </p>
<h2>Замена первого найденного заданного типа, на заданный тип.</h2>
<p>Тут почти, как и при удалении, так что объяснение излишне.</p>
<pre name="code" class="cpp">
template &lt;class TList, class T, class U&gt;
struct ReplaceFirst;

template &lt;class T, class U&gt;
struct ReplaceFirst&lt;NullType, T, U&gt;
{
    typedef NullType Result;
};

template &lt;class T, class Tail, class U&gt;
struct ReplaceFirst&lt;TypeList&lt;T, Tail&gt;, T, U&gt;
{
    typedef TypeList&lt;U, Tail&gt; Result;
};

template &lt;class Head, class Tail, class T, class U&gt;
struct ReplaceFirst&lt;TypeList&lt;Head, Tail&gt;, T, U&gt;
{
    typedef TypeList&lt;Head, typename ReplaceFirst&lt;Tail, T, U&gt;::Result&gt; Result;
};
</pre>
<h2>Замена всех типов совпадающих с заданным, на другой заданный тип.</h2>
<p>Опять, как и при удалении.</p>
<pre name="code" class="cpp">
template &lt;class TList, class T, class U&gt;
struct ReplaceAll;

template &lt;class T, class U&gt;
struct ReplaceAll&lt;NullType, T, U&gt;
{
    typedef NullType Result;
};

template &lt;class T, class Tail, class U&gt;
struct ReplaceAll&lt;TypeList&lt;T, Tail&gt;, T, U&gt;
{
    typedef TypeList&lt;U, typename ReplaceAll&lt;Tail, T, U&gt;::Result&gt; Result;
};

template &lt;class Head, class Tail, class T, class U&gt;
struct ReplaceAll&lt;TypeList&lt;Head, Tail&gt;, T, U&gt;
{
    typedef TypeList&lt;Head, typename ReplaceAll&lt;Tail, T, U&gt;::Result&gt; Result;
};
</pre>
<h2>Переворот списка.</h2>
<p>Тут нам поможет ранее написанный Append.<br />
Да кстати, уже не уделяю внимание отдельным случаям (специализациям), ибо они очевидны, это крайние случаи, и как поступать с ними, тоже вполне легко понять. Итак, берём голову, и присоединяем её к перевернутому хвосту, и всё!</p>
<pre name="code" class="cpp">
template &lt;class TList&gt;
struct Reverse;

template &lt;&gt;
struct Reverse&lt;NullType&gt;
{
    typedef NullType Result;
};

template &lt;class Head, class Tail&gt;
struct Reverse&lt;TypeList&lt;Head, Tail&gt;&gt;
{
    typedef typename Append&lt;typename Reverse&lt;Tail&gt;::Result, Head&gt;::Result Result;
};
</pre>
<p>Применение:</p>
<pre name="code" class="cpp">
typedef Reverse&lt;TYPELIST_5(int, double, char, bool, float)&gt;::Result typeReverse;
// float bool char double int
</pre>
<h2>Вставка данного типа после всех типов с номерами n + km, по данным m, n.</h2>
<p>Весело, не правда ли?<br />
Тут поступаем так: вначале уменьшаем постепенно n, ну и отщепляя каждый раз голову, когда n = 0, означает что нужно вставить сюда, вставляем, и прибавляем то, что станет с головой, после запуска вставки в ней на место n передается m, следовательно, автоматически следующий элемент вставиться после m, а дальше опять после m и т.д. Это как раз и есть n + km.</p>
<pre name="code" class="cpp">
template &lt;typename TList, typename T, std::size_t IndexM, std::size_t IndexN&gt;
struct InsertAfterNstepM
{
    typedef TList Result;
};

template &lt;typename T, std::size_t IndexM, std::size_t IndexN&gt;
struct InsertAfterNstepM&lt;NullType, T, IndexM, IndexN&gt;
{
    typedef NullType Result;
};

template &lt;typename Head, typename Tail, typename T, std::size_t IndexM&gt;
struct InsertAfterNstepM&lt;TypeList&lt;Head, Tail&gt;, T, IndexM, 0&gt;
{
    typedef TypeList&lt;Head, TypeList&lt;T, typename InsertAfterNstepM&lt;Tail, T, IndexM, IndexM - 1&gt;::Result&gt;&gt; Result;
};

template &lt;typename Head, typename Tail, typename T, std::size_t IndexM, std::size_t IndexN&gt;
struct InsertAfterNstepM&lt;TypeList&lt;Head, Tail&gt;, T, IndexM, IndexN&gt;
{
    typedef TypeList&lt;Head, typename InsertAfterNstepM&lt;Tail, T, IndexM, IndexN - 1&gt;::Result&gt; Result;
};
</pre>
<p>Применение:</p>
<pre name="code" class="cpp">
typedef InsertAfterNstepM&lt;TYPELIST_7(int, double, char, int, float, char, short), bool, 1, 1&gt;::Result typeInsertAfterNstepM;
</pre>
<h2>Удаление всех типов с номерами n + km, по данным m, n</h2>
<p>Поступаем, так же как и в предыдущем примере.</p>
<pre name="code" class="cpp">
template &lt;typename TList, std::size_t IndexM, std::size_t IndexN&gt;
struct EraseNstepM
{
    typedef TList Result;
};

template &lt;std::size_t IndexM, std::size_t IndexN&gt;
struct EraseNstepM&lt;NullType, IndexM, IndexN&gt;
{
    typedef NullType Result;
};

template &lt;typename Head, typename Tail, std::size_t IndexM&gt;
struct EraseNstepM&lt;TypeList&lt;Head, Tail&gt;, IndexM, 0&gt;
{
    typedef typename EraseNstepM&lt;Tail, IndexM, IndexM - 1&gt;::Result Result;
};

template &lt;typename Head, typename Tail, std::size_t IndexM, std::size_t IndexN&gt;
struct EraseNstepM&lt;TypeList&lt;Head, Tail&gt;, IndexM, IndexN&gt;
{
    typedef TypeList&lt;Head, typename EraseNstepM&lt;Tail, IndexM, IndexN - 1&gt;::Result&gt; Result;
};
</pre>
<h2>Разделение списка на две половины, первая до [Длина списка] / 2, во второй всё оставшееся.</h2>
<p>Тут всё немножко больше и сложнее для понимая.</p>
<p>Во-первых, у нас будет всё передаваться в Partion, который по сути сам не разделяет два списка, а обрабатывает отдельные случаи и говорит, как поступить вспомогательному PartionH, который как раз и делит, передав в него два раза один и тот же список. Сейчас объясню, для чего это делается.</p>
<p>Имея два одинаковых списка, мы в одном будем бежать со скоростью 1, а во втором со скоростью 2, т.е. отщепливать по 1, или по два символа. Понятно, что когда во втором списке останется 1 либо 0 элементов, то всё, что осталось в первом списке, будет являться второй половиной, смотрите:</p>
<p>List1: 12345 -> 2345 -> 345<br />
List2: 12345 -> 345 -> 5</p>
<p>Значит вторая половина это 345.</p>
<p>А теперь возвращаясь назад по рекурсии мы к первому списку начнём приписывать в начало элементы, которые откинулись, т.е NullType -> 2 -> 12. Итого, получаем разбиение 12 | 345.</p>
<p>Для полного понимания лучше нарисовать на листочке и проделать несколько примеров.</p>
<pre name="code" class="cpp">
template &lt;typename TList1, typename TList2&gt;
struct PartitionH;

template &lt;typename Head, typename Tail&gt;
struct PartitionH&lt;TypeList&lt;Head, Tail&gt;, NullType&gt;
{
    typedef NullType Result1;
    typedef TypeList&lt;Head, Tail&gt; Result2;
};

template &lt;typename Head, typename Tail, typename T&gt;
struct PartitionH&lt;TypeList&lt;Head, Tail&gt;, TypeList&lt;T, NullType&gt; &gt;
{
    typedef NullType Result1;
    typedef TypeList&lt;Head,Tail&gt; Result2;
};

template &lt;typename H1, typename T1, typename H2, typename T2&gt;
struct PartitionH&lt;TypeList&lt;H1, T1&gt;,TypeList&lt;H2, T2&gt; &gt;
{
    typedef typename PartitionH&lt;T1, typename T2::Tail&gt;::Result1 R1;
    typedef TypeList&lt;H1, R1&gt; Result1;
    typedef typename PartitionH&lt;T1, typename T2::Tail&gt;::Result2 Result2;
};

template &lt;typename TList&gt;
struct Partition;

template &lt;&gt;
struct Partition&lt;NullType&gt;
{
    typedef NullType Result1;
    typedef NullType Result2;
};

template &lt;typename T&gt;
struct Partition&lt;TypeList&lt;T, NullType&gt;&gt;
{
    typedef NullType Result1;
    typedef TypeList&lt;T, NullType&gt; Result2;
};

template &lt;typename TList&gt;
struct Partition
{
    typedef typename PartitionH&lt;TList, TList&gt;::Result1 Result1;
    typedef typename PartitionH&lt;TList, TList&gt;::Result2 Result2;
};
</pre>
<p>Применение:</p>
<pre name="code" class="cpp">
typedef Partition&lt;TYPELIST_5(char, short, int, long, bool)&gt;::Result1 typePart1;
typedef Partition&lt;TYPELIST_5(char, short, int, long, bool)&gt;::Result2 typePart2;
</pre>
<h2>Список типов, полученный путем инвертирования первой половины списка типов.</h2>
<p>Ну что, у нас уже есть Reverse, и у нас уже есть Partion. Несложно, правда? </p>
<pre name="code" class="cpp">
template&lt;typename TList&gt;
struct ReverseOneHalf
{
    typedef TList Result;
};

template&lt;typename Head, typename Tail&gt;
struct ReverseOneHalf&lt;TypeList&lt;Head, Tail&gt;&gt;
{
    typedef typename Append&lt;typename Reverse&lt;typename Partition&lt;TypeList&lt;Head, Tail&gt;&gt;::Result1&gt;::Result, typename Partition&lt;TypeList&lt;Head, Tail&gt;&gt;::Result2&gt;::Result Result;
};
</pre>
<p>На самом деле должно было быть ещё 10 примеров, но простите, утомился. Их можно придумывать бесконечно, но думаю, написав штучек 20, вы точно поймёте всю суть!</p>
<p>Ну и скажу, что вместо if можно спокойно использовать конструкцию вида (OK) ? (A) : (B).</p>
<p>А теперь немножко отступления от списков типов, а просто ещё несколько примеров на вычисления при компиляции.</p>
<p>Считаем p^q. Cчитаем с конца, p^q = p * p^(q - 1).</p>
<pre name="code" class="cpp">
template&lt;int p, int q&gt;
struct Power;

template&lt;int p, int q&gt;
struct Power&lt;p, q&gt; {
    enum { value = p * typename Power&lt;p, q - 1&gt;::value };
};

template&lt;int p&gt;
struct Power&lt;p, 0&gt; {
    enum { value = 1 };
};
</pre>
<p>Применение:</p>
<pre name="code" class="cpp">
cout &lt;&lt; "5^3 = " &lt;&lt; Power&lt;5, 3>::value &lt;&lt; endl;
cout &lt;&lt; "2^10 = " &lt;&lt; Power&lt;2, 10>::value &lt;&lt; endl;
cout &lt;&lt; "3^15 = " &lt;&lt; Power&lt;3, 15>::value &lt;&lt; endl;
</pre>
<p>Возвращает значение 1, если второй список является подпоследовательностью первого, в противном случае возвращает значение 0.</p>
<p>Вот это тоже интересно! Код прилагается, а насчет подумать как работает, это вы сами.</p>
<pre name="code" class="cpp">
template&lt;typename TList1, typename TList2&gt;
struct Subsequence;

template&lt;&gt;
struct Subsequence&lt;NullType, NullType&gt;
{
    enum { value = 1 };
};

template&lt;typename TList&gt;
struct Subsequence&lt;TList, NullType&gt;
{
    enum { value = 1 };
};

template&lt;typename TList&gt;
struct Subsequence&lt;NullType, TList&gt;
{
    enum { value = 0 };
};

template&lt;typename H1, typename T1, typename T2&gt;
struct Subsequence&lt;TypeList&lt;H1, T1&gt;, TypeList&lt;H1, T2&gt;&gt;
{
    enum { value = typename Subsequence&lt;T1, T2&gt;::value };
};

template&lt;typename H1, typename T1, typename H2, typename T2&gt;
struct Subsequence&lt;TypeList&lt;H1, T1&gt;, TypeList&lt;H2, T2&gt;&gt;
{
    enum { value = typename Subsequence&lt;T1, TypeList&lt;H2, T2&gt;&gt;::value };
};
</pre>
<h2>Ну и домашнее задание, придумать, как найти пересечение двух списков!</h2>
<p>Это то, что я прохожу по программированию на 2 курсе, в 1 семестре.</p>
<p>А вот и все исходники, их там гораздо больше, чем описано тут:</p>
<p><a href='http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/ListOfTypes.h'>ListOfTypes Header File</a></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2011/11/24/infinity-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

