代码之家  ›  专栏  ›  技术社区  ›  NanoWizard

C++ CONEXPRPR数组查找:内存开销?其他哥特查?

c++
  •  -1
  • NanoWizard  · 技术社区  · 7 年前

    我已经实现了一个constexpr 地图 this SO answer ,但现在我想知道如果 地图 数组非常大,使用这种技术可能存在哪些其他问题,特别是在编译时无法解析constexpr函数的情况下。

    下面是一个精心设计的代码示例,希望能让我的问题更清楚:

    例h:

    enum class MyEnum
    {
      X0,
      X1,
      X2,
      X3,
      X4,
      X5
    };
    
    struct MyStruct
    {
      const MyEnum type;
      const char* id;
      const char* name;
      const int size;
    };
    
    namespace
    {
      constexpr MyStruct myMap[] = {
        {MyEnum::X0,"X0","Test 0", 0},
        {MyEnum::X1,"X1","Test 1", 1},
        {MyEnum::X2,"X2","Test 2", 2},
        {MyEnum::X3,"X3","Test 3", 3},
        {MyEnum::X4,"X4","Test 4", 4},
        {MyEnum::X5,"X5","Test 5", 5},
      };
    
      constexpr auto mapSize = sizeof myMap/sizeof myMap[0];
    }
    
    class invalid_map_exception : public std::exception {};
    
    // Retrieves a struct based on the associated enum
    inline constexpr MyStruct getStruct(MyEnum key, int range = mapSize) {
      return  (range == 0) ? (throw invalid_map_exception()):
              (myMap[range - 1].type == key) ? myMap[range - 1]:
              getStruct(key, range - 1);
    };
    

    #include <iostream>
    #include <vector>
    #include "example.h"
    
    int main()
    {
      std::vector<MyEnum> enumList = {MyEnum::X0, MyEnum::X1, MyEnum::X2, MyEnum::X3, MyEnum::X4, MyEnum::X5};
      int idx;
    
      std::cout << "Enter a number between 0 and 5:" << std::endl;
      std::cin >> idx;
    
      MyStruct test = getStruct(enumList[idx]);
    
      std::cout << "choice name: " << test.name << std::endl;
    
      return 0;
    }
    

    输出:

    Enter a number between 0 and 5:
    1
    choice name: Test 1
    

    编撰 g++ -std=c++14 .

    在上面的例子中,虽然 getStruct idx 直到那时才知道。这可能会改变使用优化标志编译时的内存开销,或者 myMap 是否包含在二进制文件中?它是否取决于所使用的编译器和优化设置?

    另外,如果头文件包含在多个翻译单元中,该怎么办?将 我的地图 每一个都是重复的吗?

    我想如果 地图 阵列变得巨大,并且/或者代码将用于资源更为有限的环境,例如嵌入式设备。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Artyer    7 年前

    如果使用非常量表达式调用constexpr函数,它将在运行时调用该函数。

    如果你打电话 getStruct 使用常量表达式,编译器可以在编译时调用函数。然后, getStruct 函数将在运行时“未使用”,编译器可能会对其进行优化。在这一点上,, myMap 也将不使用,并进行优化。

    就运行时大小而言,它实际上可能比 std::unordered_map 或 std::map

    如果您想使它更可能被优化,我将确保它仅用于持续表达的情况:

    template<MyEnum key>
    struct getStruct
    {
        static constexpr const MyStruct value = _getStruct(key);
    }
    

    Here's some compiler output that shows that the map is optimised out entirely

    关于在多个翻译单元中包含它,它将在每个单元中重复,因为您使用匿名名称空间来定义它。如果在所有这些单元中都进行了优化,那么就不会有开销,但是对于您在其中执行运行时查找的每个翻译单元,它仍然是重复的。