static const成员变量初始化

时间:2014-07-17 08:42:15

标签: c++ class static-members

看起来我可以初始化一个POD静态const成员,但不是其他类型:

struct C {
  static const int a = 42;      // OK
  static const string b = "hi"; // compile error
};

为什么?

4 个答案:

答案 0 :(得分:5)

string不是原始类型(如int),但是是一个类。

禁止这是明智的; static的初始化发生在main之前。构造函数可以调用初始化时可能无法使用的各种函数。

答案 1 :(得分:4)

语法initializer in the class definition仅允许使用整数和枚举类型。对于std::string,它必须在类定义之外定义并在那里初始化。

struct C {
  static const int a = 42;     
  static const string b; 
};

const string C::b = "hi"; // in one of the .cpp files
必须在一个翻译单元中定义

static members才能实现一个定义规则。如果C ++允许以下定义;

struct C {
  static const string b = "hi"; 
};

b将在包含头文件的每个翻译单元中定义。

C ++只允许在类声明中将const staticintegral类型的enumeration数据成员定义为快捷方式。无法定义其他类型的const static数据成员的原因是需要进行非平凡的初始化(需要调用构造函数)。

答案 2 :(得分:2)

我将总结关于C ++ 98与C ++ 11的直接类初始化的规则:

以下代码在C ++ 03中是非法的,但可以像在C ++ 11中一样工作。在C ++ 11中,您可以将其视为注入POD的每个构造函数的初始化器,除非该构造函数设置另一个值。

struct POD {
    int integer = 42; 
    float floating_point = 4.5f;
    std::string character_string = "Hello";
};

使字段可变静态成员将破坏两个标准中的代码,这是因为static保证只有变量的一个副本,因此我们必须在一个文件中声明成员,就像我们使用extern关键字引用的全局变量一样。

// This does not work
struct POD {
    static int integer = 42;
    static float floating_point = 4.5f;
    static std::string character_string = "Hello";
};

int   POD::integer = 42;
float POD::floating_point = 4.5f;
std::string POD::character_string = "Hello";

// This works
struct POD {
    static int integer;
    static float floating_point;
    static std::string character_string;
};

int   POD::integer = 42;
float POD::floating_point = 4.3f;
std::string POD::character_string = "hello";

如果我们尝试制作它们,const静态成员会产生一系列新的规则:

struct POD {
    static const int integer = 42;               // Always works
    static constexpr float floating_point = 4.5f;    // Works in C++11 only.
    static const std::string character_string = "Hello"; // Does not work.
    constexpr static const std::string character_string = "Hello"; // Does not work (last checked in C++11)

    // Like some others have also mentioned, this works.
    static const std::string character_string;
};

// In a sourcefile:
const std::string POD::character_string = "Hello";

因此,从C ++ 11开始,允许使非整数平凡类型的静态常量变量。不幸的是,字符串不符合要求,因此即使在C ++ 11中也无法初始化constexpr std :: strings。

尽管如此,作为对this post提及的答案,你可以创建一个字符串类函数作为字符串文字。

NB!请注意,如果对象在类中声明为constexpr static,那么这是最好的元编程,然后,只要输入运行时,就无法找到该对象。我还没弄清楚原因,请随时评论一下。

// literal string class, adapted from: http://en.cppreference.com/w/cpp/language/constexpr
class conststr {
    const char * p;
    std::size_t sz; 
    public:
    template<std::size_t N>
        constexpr conststr(const char(&a)[N]) : p(a), sz(N-1) {}
    // constexpr functions signal errors by throwing exceptions from operator ?:
    constexpr char operator[](std::size_t n) const {
        return n < sz ? p[n] : throw std::out_of_range("");
    }   
    constexpr std::size_t size() const { return sz; }

    constexpr bool operator==(conststr rhs) {
        return compare(rhs) == 0;
    }   

    constexpr int compare(conststr rhs, int pos = 0) {
        return ( this->size() < rhs.size() ? -1 :
                    ( this->size() > rhs.size() ? 1 : 
                        ( pos == this->size()  ? 0 : 
                            ( (*this)[pos] < rhs[pos] ? -1 :
                                ( (*this)[pos] > rhs[pos] ? 1 : 
                                    compare(rhs, pos+1)
                                )   
                            )   
                        )   
                    )   
                );  
    }   

    constexpr const char * c_str() const { return p; }
};

现在您可以直接在您的班级中声明一个conststr:

struct POD {
    static const int integer = 42;               // Always works
    static constexpr float floating_point = 4.5f;          // Works in C++11 only.
    static constexpr conststr character_string = "Hello"; // C++11 only, must be declared.
};  



int main() {
    POD pod; 

    // Demonstrating properties.
    constexpr conststr val = "Hello";
    static_assert(val == "Hello", "Ok, you don't see this.");
    static_assert(POD::character_string == val, "Ok");
    //static_assert(POD::character_string == "Hi", "Not ok.");
    //static_assert(POD::character_string == "hello", "Not ok.");

    constexpr int compare = val.compare("Hello");
    cout << compare << endl;

    const char * ch = val.c_str(); // OK, val.c_str() is substituted at compile time.
    cout << ch << endl;   // OK

    cout << val.c_str() << endl; // Ok

    // Now a tricky one, I haven't figured out why this one does not work:
    // cout << POD::character_string.c_str() << endl; // This fails linking.

    // This works just fine.
    constexpr conststr temp = POD::character_string;
    cout << temp.c_str() << endl;
} 

答案 3 :(得分:0)

在 C++17 中:

如果您可以使用 static constexpr,您将获得所需的结果,但如果您不能:使用 C++17 引入的 inline variable

在您的情况下,由于 std::string 没有 constexpr 构造函数,因此解决方案是 inline static const std::string

示例:

#include <iostream>

int foo() { return 4;}

struct Demo
{
   inline static const int i = foo();  
   inline static const std::string str = "info";  

    
};
int main() {
    std::cout << Demo::i << " " << Demo::str<< std::endl;
    
}

Live Demo