从其他类的静态数据成员初始化映射

时间:2019-02-02 03:08:40

标签: c++ c++11

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

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时正在创建的类的临时对象,是否保证始终具有定义的行为?

3 个答案:

答案 0 :(得分:1)

似乎您可能正在使用类名实现某种反射机制。为什么不真正地获取类名作为名称?

看看:

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

接受的答案那里允许编写get_name<A>(),并得到一个字符串(_view),它是 “A”。 get_name<B>()将是“ B”,依此类推。这可能对您有用,因为:

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

答案 1 :(得分:0)

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

这是说,你的静态常量成员必须的初始化的类定义后,通常是这样的:

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

答案 2 :(得分:0)

保证只能工作

  • 地图被在所述静态成员的定义相同的编译单元中定义(例如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;
}

保证此方法有效,因为 local 静态变量是在首次使用时初始化的(甚至在C ++ 11中甚至针对多线程问题也得到了自动保护)。