【问题标题】:building and accessing a list of types at compile time在编译时构建和访问类型列表
【发布时间】:2013-09-09 15:29:10
【问题描述】:

我正在尝试使用 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 解析为包含 Foo 和 Bar 类型的列表的某种表示形式(例如 boost::mpl::vector),我就可以将任何代码插入到上面的插槽中。以下限制适用:

  1. foo.h 中的代码不应该知道 bar.h 中的代码,反之亦然。应该可以更改 main.h 中#include 指令的顺序而不更改任何其他代码。

  2. 如果我包含向列表添加更多类型的更多标头,则 main.h 中的代码不必更改。

  3. 类型列表必须在编译时可用。我正计划对列表进行进一步的元编程。

【问题讨论】:

  • @Jarod42 std::tuple 对此有何帮助?第 2 点是一个非常明智的要求——这使得代码可以扩展而无需更改现有代码。
  • @AdamBurry:主要挑战是以这种方式建立列表的方法。 表示类型列表的方法有很多(例如 boost::mpl::vector 或您提到的可能性),但这不是核心问题。
  • 在我看来,您需要在标头中使用代码来将类型注册到类型列表中。

标签: c++ template-meta-programming


【解决方案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;
}

【讨论】:

  • 啊,是的。使用预处理器符号来存储列表不断变化的全局“状态”是个好主意。顺便说一句,我希望能够用像 REGISTER_TYPE 这样的宏来包装放入 foo.h 和 bar.h 中的代码,但我想这个方案不太可能。不过你肯定回答了我的问题 - 谢谢!
  • 我找到了一个不同的解决方案,它只需要不包含宏,请参阅stackoverflow.com/a/24092292/1020667
  • 这需要Void 类型吗?你不能只专注于List&lt;&gt; 而不是List&lt;Void&gt;
【解决方案2】:
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;
}

【讨论】:

  • 请添加关于您的答案的解释,这样人们就不会知道为什么它是一个好答案。
  • 只是对上述方案的一个小改进,通过使用initializer_list,你不必编写3个info()来扩展模板参数。
  • 这与问题有什么关系?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 2019-01-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多