【问题标题】:Initialization of map from static data member of other classes从其他类的静态数据成员初始化映射
【发布时间】:2019-06-26 15:04:09
【问题描述】:

我们有一些类将静态数据成员暴露为公共成员,例如

class A{
public:
    static const string NAME;
    //Other class specific methods
};

类似的B类和其他一些类。

如果我必须创建类似的地图

static const map<string, string> versionMap = {{A().NAME, "Aa"},
                                               {B().NAME, "Bb"}
                                              };

在创建 versionMap 时创建的类的临时对象,是否保证始终具有定义的行为?

【问题讨论】:

  • 因为它是静态的,你不需要一个对象来访问它。只需使用A::NAMEB::NAME 等即可。但这并不能解决静态变量初始化顺序的问题。
  • 我会尽可能避免使用动态分配的数据结构作为静态成员。请记住,它们不能用于 constexpr 工作......为什么不将其设为 std::string_view

标签: c++ c++11


【解决方案1】:

只有在以下情况下才能保证工作

  • 映射在定义静态成员的同一编译单元中定义(例如A.cpp
  • 映射是在定义静态数据成员之后定义的

然而,你是在​​玩火......与其依赖于静态初始化顺序,不如使用在 静态成员函数中定义的 local static 变量;即

// File A.h

struct A {
    static const std::string& NAME();
};

// File Map.cpp

std::map<std::string, std::string> x{{A::NAME(), "A"}};

// File A.cpp

static const std::string& A::NAME() {
    static std::string x = "A string";
    return x;
}

因为本地静态变量在第一次使用时被初始化(甚至在 C++11 中针对多线程问题自动进行保护),所以这种方法可以保证工作。

【讨论】:

    【解决方案2】:

    您似乎正在使用类名实现某种反射机制。为什么不实际获取类名,作为名字?

    看看:

    Can I obtain C++ type names in a constexpr way?

    那里接受的答案允许您编写get_name&lt;A&gt;() 并获得一个字符串(_view),它是“A”。而get_name&lt;B&gt;() 将是“B”等等。这可能对您的情况有用,因为:

    1. 没有动态分配的数据。
    2. 不构造任何对象(尽管@jhill515 也为您提供)
    3. 不需要静态成员 - 这可以与您甚至无法控制的类一起使用!

    【讨论】:

      【解决方案3】:

      当您定义一个类的静态成员时,无论该类是否被实例化,该成员都可以通过内存访问。在这种情况下,由于它们是公共成员,因此使用字符串本身作为键是完全有效的。

      也就是说,您的静态常量成员需要在类定义之后初始化,通常类似于:

      class Foo { static const int foo; };
      const int Foo::foo = 42;
      

      对于您的静态地图示例,您需要记住,如果将地图用作类成员,则必须类似地初始化该地图。这是一个工作示例:

      // Compiled with g++ --std=c++17 -Wall -Wextra -Werror ConstStaticMapExample.cpp -o ConstStaticMapExample
      #include <iostream>
      #include <string>
      #include <map>
      
      class A
      {
      public:
        static const std::string NAME;
        //Other class specific methods
      };
      const std::string A::NAME = "foo";
      
      class B
      {
      public:
        static const std::string NAME;
        //Other class specific methods
      };
      const std::string B::NAME = "bar";
      
      class C
      {
      public:
        static const std::map<std::string, std::string> versionMap;
        // More definitions
      };
      const std::map<std::string, std::string> C::versionMap = {{A::NAME,"aA"},{B::NAME,"bB"}}; // Reversed for explanation
      
      int main(int,char**)
      {
        // local static
        static const std::map<std::string, std::string> versionMap = {{A::NAME,"Aa"},{B::NAME,"Bb"}};
        std::cout << "LOCAL STATIC EXAMPLE:" << std::endl;
        for(auto mpair : versionMap)
        {
          std::cout << "Key: " << mpair.first << "\tVal: " << mpair.second << std::endl;
        }
      
        // class member static
        std::cout << "CLASS MEMBER STATIC EXAMPLE:" << std::endl;
        for(auto mpair : C::versionMap)
        {
          std::cout << "Key: " << mpair.first << "\tVal: " << mpair.second << std::endl;
        }
      
        return 0;
      }
      

      Gist

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-01
        • 2011-07-18
        • 2021-12-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多