Комментарии 18
Она, мне лично, больше нравится, так как позволяет писать
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 были созданы чтобы избавиться от списков типов, а вы их конвертируете в список типов, зачем? При этом работа с вариадиками куда как проще чем со списком типов. По сути чтобы сохранить вариадик, его надо упаковать либо в пустой тип, либо как вариант в тип функции.
Ну и распаковать их очень легко
Ну и есть еще std::tuple. Попробуйте избавиться от списков типов и сразу заметите как упростится код, да и увеличится скорость компиляции. Ну и по сути если хотите работать с вариадиками, ни в коем случае не отталкивайтесь от книги Александреску, в этом случае увы, она только вредна, ибо механизмы работы другие. Можете поглядеть старую версию моей либы github.com/axispod/vmpl, увы заточена пока под VS, не хватает времени довести до ума. Есть простенькие алгоритмы для работы с вариадиками.
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 — интерессная штука. Где-то применяли?
Глянул Вашу либу, с map — интерессная штука. Где-то применяли?
Проблема не в том, что у вас списки типов вместо вариадиков. У вас списки типов поверх вариадиков. И вот от этого уже сносит крышу окончательно. Если вы такой бедный несчастный, что вам нужно поддерживать какой-нибудь проект для MSVC 2010 и вариадиков у вас просто нету — ну Ok, вам можно посочувствовать, но да, придётся мучиться. Но если вы уже начали использовать варидики, то, я извиняюсь, зачем поверх них-то списки типов городить? Где-то мы это уже видели:
Скрытый текст
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;
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Инстанциирование шаблонов функций по списку типов (Часть 1)