static const成员变量初始化

Deq*_*ing 9 c++ class static-members

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

struct C {
  static const int a = 42;      // OK
  static const string b = "hi"; // compile error
};
Run Code Online (Sandbox Code Playgroud)

为什么?

Alp*_*per 7

该语法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
Run Code Online (Sandbox Code Playgroud)

static members必须在一个翻译单元中定义才能满足一个定义规则。如果 C++ 允许下面的定义;

struct C {
  static const string b = "hi"; 
};
Run Code Online (Sandbox Code Playgroud)

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

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


Bat*_*eba 5

string不是原始类型(如int),而是一个类.

不允许这样做是明智的; statics 的初始化发生在之前main.构造函数可以调用初始化时可能无法使用的各种函数.

  • "构造函数可以调用初始化时可能无法使用的各种函数"?这意味着还应该禁止全局对象(即全局非原始变量)(正如您所知,并非如此). (4认同)
  • 这不是真的 - 你可以在这样的其他范围初始化常量.它也没有解释像`const char*`这样的其他原语. (2认同)

Sti*_*org 5

我将在 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";
};
Run Code Online (Sandbox Code Playgroud)

使字段可变静态成员将破坏两个标准中的代码,这是因为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";
Run Code Online (Sandbox Code Playgroud)

如果我们试图让它们, 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";
Run Code Online (Sandbox Code Playgroud)

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

尽管如此,一切都没有丢失,正如本文提到的答案,您可以创建一个字符串类函数作为字符串文字。

注意!请注意,这是最好的元编程,如果在类中将对象声明为 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; }
};
Run Code Online (Sandbox Code Playgroud)

现在你可以直接在你的类中声明一个 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;
} 
Run Code Online (Sandbox Code Playgroud)