【问题标题】:Compile-time template `std::integral_constant` counter - how to implement it?编译时模板`std::integral_constant`计数器 - 如何实现它?
【发布时间】:2014-09-18 15:36:31
【问题描述】:

我有几种类型,我想在编译时将std::integral_constant 顺序 ID 值“绑定”到每种类型。

例子:

struct Type00 { };
struct Type01 { };
struct Type02 { };
struct Type03 { };
struct TypeXX { };
struct TypeYY { };

template<typename T> struct TypeInfo
{
    using Id = std::integral_constant<int, ???>;
};

int main()
{
     cout << TypeInfo<Type00>::Id::value; // Should always print 0
     cout << TypeInfo<Type01>::Id::value; // Should always print 1
     cout << TypeInfo<Type02>::Id::value; // Should always print 2
     cout << TypeInfo<Type03>::Id::value; // Should always print 3
     cout << TypeInfo<TypeXX>::Id::value; // Should always print 4
     cout << TypeInfo<TypeYY>::Id::value; // Should always print 5
}

问题在于我不知道如何跟踪上次使用的 ID。理想情况下,我想要这样的东西:

template<typename T> struct TypeInfo
{
    using Id = std::integral_constant<int, lastUsedID + 1>;
};

有没有办法定义和跟踪编译时lastUsedID

我该如何解决这个问题?


编辑:

说明:

  • TypeInfo&lt;...&gt; 需要在用户代码中频繁调用。语法必须保持清晰(用户不需要(需要知道有一个/手动增加)编译时计数器)
  • Typeinfo&lt;T&gt;::Id::value 必须始终在整个程序中返回相同的值。初始值将在第一次实例化时“绑定”到lastUsedID + 1
  • 我可以使用所有 C++11 和 C++14 功能。
  • 在调用TypeInfo&lt;...&gt; 之前列出所有类型不是一个合适的解决方案。

【问题讨论】:

  • 您可以在下一个继承每个连续的并递增。什么的。
  • 编译单元(不同的源文件)之间如何,需要值一致吗?不重叠?你愿意在某处列出所有类型的清单吗?它们必须是连续的还是唯一的?知道你可以采取的确切位置比所有人都少,可以让你的问题更容易解决。
  • 你可能对this answer感兴趣。
  • 如果可以在不同的头文件中定义类型,那么我很确定标准 C++ 中没有办法拥有连续的编译时常量类型 ID,这些 ID 保证在整个程序,而不提供明确的类型列表。这是因为程序的不同部分是分开编译的。如果a.cpp 包含TypeInfo&lt;A&gt;; TypeInfo&lt;B&gt;; 并且b.cpp 包含TypeInfo&lt;B&gt;; TypeInfo&lt;A&gt;;,那么读取时反增量方法将产生不同的ID。你需要放弃一个你的要求。

标签: c++ templates c++11 c++14 constexpr


【解决方案1】:

这是不可能的,而且很容易看出原因:考虑两个编译单元。单元一看到类型Type00,但看不到Type01,而单元二看到Type01,但看不到Type00。 C++(包括 C++11 和 C++14)中没有任何内容现在可以告诉编译器在两个编译单元中这些类型应该具有的顺序。即使将一些数据添加到链接时的目标文件也为时已晚,因为您要求的是编译时值。这是编译单元的基本概念,它对您要求的功能构成了硬障碍。

【讨论】:

  • 我明白了,谢谢。在授予赏金之前,我还有一个问题:由于无法在编译时执行我想要的操作,即使在多个编译单元的情况下,this implementation using static storage 是否可以接受且安全?
  • @VittorioRomeo 是的,它有效,但它是另一回事。静态存储不是编译时值,它是加载时初始化的静态 (const) 值。它不能用作真正的编译时值,例如,用作模板参数。
  • 我知道这一点。我只是想确保这种“解决方法”在多个编译单元中没有问题。
  • @VittorioRomeo 正如我所说,它可以工作 - 这意味着多个编译单元应该没有问题(当然错误总是可能的)。我只是试图强调差异在哪里,以及您的技术如何通过将值的计算延迟到稍后阶段来避免原始问题的问题。
【解决方案2】:

您可以使用类型列表来做到这一点:

template <typename... Ts>
struct TypeList;

template <>
struct TypeList<>
{
    static const int size = 0;
    static std::integral_constant<int, -1> indexOf(...);
};

template <typename Head, typename... Tail>
struct TypeList<Head, Tail...> : TypeList<Tail...>
{
    static const int size = sizeof...(Tail) + 1;
    static std::integral_constant<int, sizeof...(Tail)> indexOf(Head&&);
    using TypeList<Tail...>::indexOf;
};

template <typename TypeList, typename T>
using IndexOf = std::integral_constant<int,
    TypeList::size - decltype(TypeList::indexOf(std::declval<T>()))::value - 1>;

如果T 不存在于List 中,那么IndexOf&lt;List, T&gt;::value 就是-1。您可以通过从签名 TypeList&lt;&gt;::indexOf(...) 中删除省略号来使这种情况成为编译错误。

用法:

struct Type00 { };
struct Type01 { };
struct Type02 { };
struct Type03 { };
struct TypeXX { };
struct TypeYY { };

using MyTypeList = TypeList<
    Type00,
    Type01,
    Type02,
    Type03,
    TypeXX,
    TypeYY
>;

int main()
{
    std::cout << IndexOf<MyTypeList, Type00>::value
              << IndexOf<MyTypeList, Type01>::value
              << IndexOf<MyTypeList, Type02>::value
              << IndexOf<MyTypeList, Type03>::value
              << IndexOf<MyTypeList, TypeXX>::value
              << IndexOf<MyTypeList, TypeYY>::value;
}

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-21
    • 1970-01-01
    • 2014-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多