首頁 >後端開發 >C++ >為什麼'B::getB()”無法在具有靜態成員的模板類別中初始化'mB”?

為什麼'B::getB()”無法在具有靜態成員的模板類別中初始化'mB”?

Linda Hamilton
Linda Hamilton原創
2024-10-31 05:59:02531瀏覽

 Why Does `B::getB()` Fail to Initialize `mB` in Templated Classes with Static Members?

模板中的靜態成員初始化:深入研究

在C 中,嵌套輔助結構的靜態成員初始化通常對於非模板化類別來說不會出現問題。但是,當封閉類別被模板化時,如果在主程式碼中未存取輔助對象,則會出現潛在的怪癖。

模板化類別的問題

考慮以下簡化範例:

<code class="cpp">struct A
{
    struct InitHelper
    {
        InitHelper()
        {
            A::mA = "Hello, I'm A.";
        }
    };
    static std::string mA;
    static InitHelper mInit;

    static const std::string& getA(){ return mA; }
};

template<class T>
struct B
{
    struct InitHelper
    {
        InitHelper()
        {
            B<T>::mB = "Hello, I'm B.";
        }
    };
    static std::string mB;
    static InitHelper mInit;

    static const std::string& getB() { return mB; }
    static InitHelper& getHelper(){ return mInit; }
};</code>

這裡,嵌套的 InitHelper 初始化 A 的靜態成員 mA 和 B 的 mB。

當我們嘗試初始化模板類別 B 中的成員時,就會出現問題。使用getB 方法如下所示,不會觸發mB 的初始化:

<code class="cpp">std::cout << "B = " << B<int>::getB() << std::endl;</code>

發生這種情況是因為,根據ISO/IEC C 2003 標準(14.7.1),僅發生靜態資料成員的初始化當成員本身以需要其定義的方式使用。在這種情況下,由於 mB 僅在模板類別的 getB() 方法中引用,因此編譯器不會隱式實例化其定義。

隱式實例化和明確特殊化

要了解編譯器的行為,澄清隱式實例化的概念很重要。對於範本中的靜態資料成員,隱式實例化會實例化聲明,但不會實例化定義。只有當靜態資料成員以需要其定義(例如賦值)的方式使用時,實際的初始化(建構函式呼叫)才會發生。

另一方面,明確專業化在命名空間或類別中使用明確聲明,其中已命令初始化。換句話說,專用的靜態資料成員始終在其類別模板的任何實例化之前初始化。

答案

在您的特定程式碼範例中,呼叫 B::getHelper()觸發 mB 和 mInit 的初始化,因為 getHelper 傳回 mInit 的引用,這需要 InitHelper 存在。

但是,依賴初始化的順序是未定義的行為。正確的解是顯式特化類別 B 中的靜態資料成員 mInit。這將確保始終建立輔助對象,並且 B 的任何後續實例化都將正確初始化其靜態資料成員。

結論

總而言之,C 模板中的靜態成員初始化需要仔細考慮。隱式實例化僅實例化聲明,而不實例化定義。為了有序且可靠的初始化,在處理包含靜態資料成員的模板化類別時應考慮明確專業化。

以上是為什麼'B::getB()”無法在具有靜態成員的模板類別中初始化'mB”?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn