Создание и доступ к списку типов во время компиляции
Я пытаюсь добиться следующего с помощью метапрограммирования шаблонов C++. Я хочу создать список типов, а затем собрать их вместе и выполнить дальнейшую обработку во время компиляции в этом списке. Так, например:
foo.h:
class Foo { ... };
// INSERT ANY CODE HERE
bar.h:
class Bar { ... };
// INSERT ANY CODE HERE
main.h:
#include "foo.h"
#include "bar.h"
struct list_of_types {
typedef /* INSERT ANY CODE HERE */ type;
};
Я могу вставить любой код в указанные выше слоты, если list_of_types:: type разрешается в некотором представлении (например, boost:: mpl:: vector) списка, содержащего типы Foo и Bar. Применяются следующие ограничения:
Код в foo.h не должен знать о коде в bar.h, и наоборот. Должна быть возможность изменить порядок директив #include в main.h и не изменять какой-либо другой код.
Код в main.h не должен изменяться, если я включаю дополнительные заголовки, которые добавляют дополнительные типы в список.
Список типов должен быть доступен во время компиляции. Я планирую сделать дальнейшее метапрограммирование с использованием списка.
1 ответ
Решение, использующее общий заголовок, шаблоны переменных и макрос:
// Header common.h
// A distinct Void type
struct Void {};
template <typename ...> struct concat;
template <template <typename ...> class List, typename T>
struct concat<List<Void>, T>
{
typedef List<T> type;
};
template <template <typename ...> class List, typename ...Types, typename T>
struct concat<List<Types...>, T>
{
typedef List<Types..., T> type;
};
template <typename...> struct TypeList {};
template <>
struct TypeList<Void> {};
typedef TypeList<Void> TypelistVoid;
#define TYPE_LIST TypelistVoid
// Header foo.h
#include <common.h>
class Foo { };
typedef typename concat<TYPE_LIST, Foo>::type TypeListFoo;
#undef TYPE_LIST
#define TYPE_LIST TypeListFoo
// Header bar.h
#include <common.h>
class Bar { };
typedef typename concat<TYPE_LIST, Bar>::type TypeListBar;
#undef TYPE_LIST
#define TYPE_LIST TypeListBar
// Header main.h
#include "foo.h"
#include "bar.h"
struct list_of_types {
typedef TYPE_LIST type;
};
// Or just typedef TYPE_LIST list_of_types;
// Test
#include <iostream>
#include <typeinfo>
template <template <typename ...> class List, typename T, typename ...Types>
void info();
template <typename T, typename ...Types>
inline void info(TypeList<T, Types...>) {
std::cout << typeid(T).name() << std::endl;
info(TypeList<Types...>());
}
template <typename T>
inline void info(TypeList<T>) {
std::cout << typeid(T).name() << std::endl;
}
int main() {
info(list_of_types::type());
return 0;
}
template <typename ... Types>
void info(TypeList<Types...>) {
std::initializer_list<std::string> ls { typeid(Types).name() ... };
for (auto& name : ls)
std::cout << name << std::endl;
}
int main() {
info(TYPE_LIST());
return 0;
}