【问题标题】:How to use a templated alias or const variable to abbreviate a static const variable?如何使用模板化别名或 const 变量来缩写静态 const 变量?
【发布时间】:2021-05-06 06:27:01
【问题描述】:

我正在编写一个实体组件系统作为 C++17 的练习。我想让每个组件类型(表示为一个结构)与一个唯一标识符相关联,该标识符可用作组件注册表中位集向量的索引,例如。这可以使用模板结构ComponentType。但是,每次我想获得价值时,写ComponentType<Tag>::type 感觉很冗长。我更喜欢使用component_type_t<Tag> 之类的东西。但是,使用模板化别名和如下实现会失败,尽管它会编译,但使用会产生以下输出。有没有更好的方法来解决这个问题?

0
1
2
0
0
0

代码:

#include <iostream>
    
namespace ECS {
    struct ComponentTraits {
        using component_type = unsigned int;
    protected:
        static component_type types;
    };

    using component_type = ComponentTraits::component_type;
    component_type ComponentTraits::types = 0;

    template<typename Component> 
    struct ComponentType : public ComponentTraits {
        static const component_type type;
    };

    template<typename Component>
    const component_type ComponentType<Component>::type = types++;

    template<typename Component>
    const component_type component_type_t = ComponentType<Component>::type;

    //Components
    struct Tag {};
    struct Transform {};
    struct Mesh {};
    // and so on...
  
    ////Won't compile
    //template<typename Component>
    //using component_type_t = ComponentType<Component>::type;
};

int main() {
    using namespace ECS;

    std::cout << ComponentType<Tag>::type << std::endl;
    std::cout << ComponentType<Transform>::type << std::endl;
    std::cout << ComponentType<Mesh>::type << std::endl;

    std::cout << component_type_t<Tag> << std::endl;
    std::cout << component_type_t<Transform> << std::endl;
    std::cout << component_type_t<Mesh> << std::endl;

    return 0;
}

【问题讨论】:

  • template&lt;typename Component&gt; using component_type_t = decltype(ComponentType&lt;Component&gt;::type);
  • 首先我的朋友你的问题是一点点工资,其次当我运行你的代码时,我得到不同的输出:0 1 2 0 1 2
  • @newbie 也许这是特定于编译器的。但是,我使用的是 Visual Studio 2019,它会产生该输出。

标签: c++ templates static c++17 entity-component-system


【解决方案1】:

您的模板化 using 未编译的原因是您的 ComponentType 不包含别名,它包含变量存储。

using component_type = unsigned int;
static const component_type type; // this is not an alias

template<typename Component>
using component_type_t = ComponentType<Component>::type;

要修复该错误,您需要使用 decltype 获取其类型:

template<typename Component>
using component_type_t = decltype(ComponentType<Component>::type);

但这又引发了另一个问题,component_type_t 实际上从未保存过您期望的值,它实际上保存了component_type,即unsigned int,没有为其分配任何值(因为它是别名),所以当您调用时:

std::cout << component_type_t<Tag> << std::endl;
std::cout << component_type_t<Transform> << std::endl;
std::cout << component_type_t<Mesh> << std::endl;

它打印 0 因为你的编译器将 0 分配给未初始化的变量,你不应该依赖这个,因为不同的编译器可能会以不同的方式处理这个。

所以要解决这个问题,你需要将值传递给变量而不是传递它的类型:

template<typename T>
component_type component_type_t<T> = ComponentType<T>::type;

你的输出将是:

0 // Tag 
1 // Transform
2 // Mesh
0 // Tag 
1 // Transform
2 // Mesh

【讨论】:

  • 很遗憾,我无法建立您的建议。相反,我在一些摆弄之后发现,我使用 component_type_t 的 const 引用获得了所需的输出。
  • 你用的是什么编译器?因为我在 GCC/Clang 上对其进行了测试,并且运行良好。
  • 我正在使用 Microsoft Visual C++ 编译器。
  • 我已经在我的机器上的 Visual Studio 上对其进行了测试,它产生了你的结果......显然,GCC/Clang 知道如何在未指定定义时将自己重定向到正确的变量。在您对ComponentType&lt;Component&gt;::type 的定义中,您错过了告诉MSVC types++ 在哪里,要解决此问题,只需将整行更改为:const component_type ComponentType&lt;Component&gt;::type = ComponentType&lt;Component&gt;::types++; 它应该可以解决您的问题。
  • 此外,由于您使用 C++17,您可能希望考虑在变量 (en.cppreference.com/w/cpp/language/static) 上应用 inline,它可以让您在处理 statics 时节省一些重复的代码。
猜你喜欢
  • 1970-01-01
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
  • 2014-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多