Как стать автором
Обновить

Комментарии 18

О том, что такое список типов можно почитать здесь

Я конечно не настаиваю, но может быть лучше дать ссылку на книгу «Современное проектирование на С++»?
По куску исходного кода из Loki тяжеловато определить назначение этого класса.
справедливо
Она, мне лично, больше нравится, так как позволяет писать
typedef TypeList<int,char,bool,string, EmptyList> MyTypeList;

Внесу и свой костыль:
template<
	typename T0 = internal::Void,
        // ...
>
struct make_typelist
{
	typedef List<T0, List<T1, List<T2, List<T3, List<T4, List<T5, List<T6, List<T7, List<T8, List<T9> > > > > > > > > > type;
};
typedef make_typelist<int, short, double, char>::type ...

Так как мне не нравится указывать что-то EmptyList-а.
А если задача состоит только в ограничении типов, которыми можно инстанциировать шаблон, то, как по мне, проще что-то такого:
template<typename T>
void foo(int x, typename std::enable_if</*Проверить, есть ли тип T в каком-то списке типов*/>::type* = NULL)
{
}

template<typename T, typename = typename std::enable_if</**/>::type>
struct Foo
{
};

Это прекрасно работает и не приходится инстанциировать весь набор, а только то, что нужно
Внесу и свой костыль:

Этот костыль можно было предвидеть. EmptyType был специально оставлен, чтобы приём с рекурсией был более понятен, если с ним кто незнаком.

Но если уже задаваться целью от него избавиться, то тогда уже можно не стесняться:
template <typename... Types> using NiceTypeList =  TypeList<Types..., EmptyList>;
typedef NiceTypeList<int, double, bool, char, const char*> MyTypeList;



А если задача состоит только в ограничении типов, которыми можно инстанциировать шаблон, то, как по мне, проще что-то такого:

В том то и дело, что основная цель состоит не в ограничении типов, а в переносе определения шаблона в исходник.
А зачем так много сложностей-то?
// file: proto.h
template<typename ... Types> struct TypeList {};

using InstTypes = TypeList<int, float, double>;

template<typename T> T foo();

// file: proto.cpp
template<typename T> T foo()
{
	return T(1);
}

template<typename T> struct Instantiator;

template<> struct Instantiator<TypeList<>> {};

template<typename T, typename ... Types> struct Instantiator<TypeList<T, Types...>>
{
	T (* const f)() = &foo<T>;
	Instantiator<TypeList<Types...>> rest;
};


static Instantiator<InstTypes> i;

// main.cpp
#include <iostream>
#include "proto.h"

int main()
{
    std::cout << foo<int>() << foo<float>() << foo<double>() << std::endl;
    return 0;
}
Верно. Во второй части как раз нечто похожем и пойдёт речь. Я хотел показать весь мыслительный путь к окончательному решению.
Этот путь кажется мне чересчур извилистым и тернистым. Какой смысл вообще откапывать TypeList в стиле Loki при наличии C++11? Если нужен просто список типов, то пользуемся непосредственно вариадиками, какие могут быть head-tail в наше тяжёлое время? Если нужна какая-то могучая работа над множествами типов, то зачем переизобретать boost::mpl?
Какая практическая задача решается «инстанциированием для определённого набора типов»?
Это, скорее не задача, а улучшение, если судьба шаблона — быть инстанциированным только для опеределённого набора типов. Улучшение заключается в переносе определения шаблона в исходник.
То есть практического применения у этой конструкции нет?
Иногда перенос инстанциаций в отдельный модуль трансляции позволяет очень сильно урезать размер кода (разумеется, за счет инлайнинга).
Ускорение компиляции, более «чистые» заголовочные файлы, возможность закрытия кода.
Странная статья, variadic templates были созданы чтобы избавиться от списков типов, а вы их конвертируете в список типов, зачем? При этом работа с вариадиками куда как проще чем со списком типов. По сути чтобы сохранить вариадик, его надо упаковать либо в пустой тип, либо как вариант в тип функции.

template<typename ... TArgs> struct holder; template<typename ... TArgs> struct vpack { typedef void(functtion_type)(TArgs...); typedef holder<TArgs...> holder_type; };
Ну и распаковать их очень легко

template<typename T> struct funpack; template<typename ... TArgs> struct funpack<void(TArgs...)> { } template<typename T> struct hunpack; template<typename ... TArgs> struct hunpack<holder<TArgs...>> { }

Ну и есть еще std::tuple. Попробуйте избавиться от списков типов и сразу заметите как упростится код, да и увеличится скорость компиляции. Ну и по сути если хотите работать с вариадиками, ни в коем случае не отталкивайтесь от книги Александреску, в этом случае увы, она только вредна, ибо механизмы работы другие. Можете поглядеть старую версию моей либы github.com/axispod/vmpl, увы заточена пока под VS, не хватает времени довести до ума. Есть простенькие алгоритмы для работы с вариадиками.
Забыл сразу сказать, что внутри возможны алгоритмы схожие по работе со списками типов, но это требуется совсем не всегда. Например это требуется при работае с элементом в определенной позиции, например разрезать вариадик на 2 отдельных куска по определенной позиции.
Если бы знал, что последуют комментарии, почему списки типов вместо вариадиков и т.д, то сразу бы написал с вариадиками. Именно с ними и будет показано решение во второй части. Здесь речь идёт о том, как добиться переноса определения шаблона в исходный файл. А какие инструменты для этого используются — это уже вторично.
Глянул Вашу либу, с map — интерессная штука. Где-то применяли?
Проблема не в том, что у вас списки типов вместо вариадиков. У вас списки типов поверх вариадиков. И вот от этого уже сносит крышу окончательно. Если вы такой бедный несчастный, что вам нужно поддерживать какой-нибудь проект для MSVC 2010 и вариадиков у вас просто нету — ну Ok, вам можно посочувствовать, но да, придётся мучиться. Но если вы уже начали использовать варидики, то, я извиняюсь, зачем поверх них-то списки типов городить? Где-то мы это уже видели:
Скрытый текст
image
map хотел применять, но в последствии придумал более оптимальный механизм и пока отказался от дальнейшего развития. В основном vmpl дописываю только по мере необходимости.
так как позволяет писать
typedef TypeList<int,char,bool,string, EmptyList> MyTypeList;
вместо классической записи
typedef TypeList<int,TypeList<char,TypeList<bool,TypeList<string, EmptyList>>>> MyTypeList;

Мне не приходилось пользоваться Loki (предпочитаю boost::mpl), но, тем не менее, я заглядывал в исходники из любопытства. Там есть мейкеры для TypeList:
typedef MakeTypelist<int,char,bool,string>::Result MyTypeList;

Также на макросах:
typedef LOKI_TYPELIST_4(int,char,bool,string) MyTypeList;
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории