静态字符串常量(类成员)(Static constant string (class member)

2019-07-23 12:55发布

我想有一类的私人静态常量(在这种情况下,一个形状厂)。

我想有类似的东西。

class A {
   private:
      static const string RECTANGLE = "rectangle";
}

不幸的是我得到了各种错误从C ++(G ++)编译器,如:

ISO C ++禁止部件的初始化“RECTANGLE”

无效一流初始化非整数类型的静态数据成员的“的std :: string”

错误:制定“矩形”静

这告诉我,这类成员设计的不符合标准的。 你怎么有,而不必使用#define指令的私人字面常量(或者公开)(我想避免数据整体性的uglyness!)

任何帮助表示赞赏。

Answer 1:

你必须定义在类定义之外的静态成员,并提供初始化那里。

第一

// In a header file (if it is in a header file in your case)
class A {   
private:      
  static const string RECTANGLE;
};

然后

// In one of the implementation files
const string A::RECTANGLE = "rectangle";

原先尝试使用(类定义中初始化)语法只与积分和枚举类型允许的。


从你有另一种选择,这非常类似于原来的声明C ++ 17起:内联变量

// In a header file (if it is in a header file in your case)
class A {   
private:      
  inline static const string RECTANGLE = "rectangle";
};

不需要额外的定义。



Answer 2:

在C ++ 11现在你可以这样做:

class A {
 private:
  static constexpr const char* STRING = "some useful string constant";
};


Answer 3:

中的类定义你只能声明静态成员。 他们必须要在类之外定义 。 对于编译时间积分常数的标准,使您可以“初始化”的成员除外。 它仍然不是一个定义,虽然。 以该地址没有定义工作,例如。

我想提一提,我没有看到使用的std :: string在为const char [] 为常量的利益。 的std :: string是好的,所有的,但它需要动态初始化。 所以,如果你喜欢写东西

const std::string foo = "hello";

在命名空间范围foo的构造将主要的执行开始之前的位置运行,此构造将在堆内存中创建常量“你好”的副本。 除非你真的需要矩形设置为std :: string,你也可以同样写

// class definition with incomplete static member could be in a header file
class A {
    static const char RECTANGLE[];
};

// this needs to be placed in a single translation unit only
const char A::RECTANGLE[] = "rectangle";

那里! 没有堆分配,没有复制,没有动态初始化。

干杯,秒。



Answer 4:

这只是额外的信息,但如果你真的想在头文件中的字符串,你可以试试:

class foo
{
public:
    static const std::string& RECTANGLE(void)
    {
        static const std::string str = "rectangle";

        return str;
    }
};

虽然我怀疑,建议。



Answer 5:

在C ++ 17,你可以使用内联变量

class A {
 private:
  static inline const std::string my_string = "some useful string constant";
};

请注意,这是从不同的abyss.7的回答 :这一个定义了一个实际std::string对象,而不是const char*



Answer 6:

要使用在级初始化语法中,常数必须由常量表达式初始化整型或枚举类型的静态常量。

这是限制。 因此,在这种情况下,你需要定义在类的外部变量。 从@AndreyT参考answwer



Answer 7:

本标准仅允许静态整型常量类型,初始化。 所以,你需要做的是AndreyT解释。 然而,将在通过下一个标准是可用的新成员初始化语法 。



Answer 8:

可能只是做:

static const std::string RECTANGLE() const {
    return "rectangle";
} 

要么

#define RECTANGLE "rectangle"


Answer 9:

您可以去的const char*上述方案中,但随后如果需要串的时候,你将有大量的开销。
在另一方面,静态字符串需要动态初始化,因此,如果你想另一个全局/静态变量的初始化过程中使用它的价值,你会打的初始化顺序的问题。 为了避免这种情况,最便宜的东西是通过一个getter,如果你的对象初始化与否,检查访问静态字符串对象。

//in a header  
class A{  
  static string s;   
public:   
  static string getS();  
};  
//in implementation  
string A::s;  
namespace{  
  bool init_A_s(){  
    A::s = string("foo");   
    return true;  
  }  
  bool A_s_initialized = init_A_s();  
}  
string A::getS(){      
  if (!A_s_initialized)  
    A_s_initialized = init_A_s();  
  return s;  
}  

请记住,只使用A::getS() 因为任何一个线程可以通过才开始main()A_s_initialized之前初始化main()你并不需要,甚至在多线程环境锁。 A_s_initialized默认为0(动态初始化之前),所以如果你用getS() s的初始化之前,您安全地调用init函数。

顺便说一下,在上面的回答是:“ 静态常量的std :: string矩形()const的 ”,静态函数不能是const ,因为他们无法改变状态,如果任何对象反正(有没有这个指针)。



Answer 10:

类的静态变量可以在头声明 ,但必须在一个.cpp文件中定义 。 这是因为只能有一个静态变量的情况下,编译器不能决定其中产生的目标文件,把它,所以你必须做出决定,而不是。

为了保持一个静态值的定义与在C ++ 11的声明可以使用嵌套静态结构。 在这种情况下静态部件是结构,并且具有在一个cpp文件中定义的,但这些值在头中。

class A
{
private:
  static struct _Shapes {
     const std::string RECTANGLE {"rectangle"};
     const std::string CIRCLE {"circle"};
  } shape;
};

相反,初始化各个成员的整体静态结构初始化中的.cpp:

A::_Shapes A::shape;

该值与访问

A::shape.RECTANGLE;

或者 - 因为成员是私有的,并打算从一个只用 - 与

shape.RECTANGLE;

请注意,这个解决方案仍然从静态变量的初始化顺序的问题的困扰。 当一个静态值用于初始化另一个静态变量,第一可能不被初始化,但。

// file.h
class File {
public:
  static struct _Extensions {
    const std::string h{ ".h" };
    const std::string hpp{ ".hpp" };
    const std::string c{ ".c" };
    const std::string cpp{ ".cpp" };
  } extension;
};

// file.cpp
File::_Extensions File::extension;

// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };

在这种情况下,静态变量标头将包含任一{“”}或{“.H”,“.HPP”},根据由链接器创建初始化的量级上。

正如@提到abyss.7你也可以使用constexpr如果变量的值可以在编译时计算。 但是,如果你申报你的字符串static constexpr const char*和程序使用std::string否则会有负担,因为一个新std::string对象将被创建每次使用这种恒定的时间:

class A {
public:
   static constexpr const char* STRING = "some value";
};
void foo(const std::string& bar);
int main() {
   foo(A::STRING); // a new std::string is constructed and destroyed.
}


Answer 11:

快进到2018和C ++ 17。

  • 不使用的std :: string,使用std :: string_view文字
  • 请注意“constexpr”波纹管。 这也是一种“编译时”机制。
  • 无内联并不意味着重复
  • 没有cpp文件是没有必要为这个
  • static_assert“工作”只有编译时

     using namespace std::literals; namespace STANDARD { constexpr inline auto compiletime_static_string_view_constant() { // make and return string view literal // will stay the same for the whole application lifetime // will exhibit standard and expected interface // will be usable at both // runtime and compile time // by value semantics implemented for you auto when_needed_ = "compile time"sv; return when_needed_ ; } 

    };

以上是适当和合法的标准C ++公民。 它可以变得容易参与任何和所有的std ::算法,容器,公用设施和这样的。 例如:

// test the resilience
auto return_by_val = []() {
    auto return_by_val = []() {
        auto return_by_val = []() {
            auto return_by_val = []() {
return STANDARD::compiletime_static_string_view_constant();
            };
            return return_by_val();
        };
        return return_by_val();
    };
    return return_by_val();
};

// actually a run time 
_ASSERTE(return_by_val() == "compile time");

// compile time 
static_assert(
   STANDARD::compiletime_static_string_view_constant() 
   == "compile time" 
 );

享受标准C ++



文章来源: Static constant string (class member)