2015-02-05 132 views
5

這初始化它是我現在有:聲明這個類聲明中一個類的實例,並就地

class CColorf 
{ 
public: 
    CColorf(); 
    CColorf(float r, float g, float b, float a = 1.0f); 

public: 
    float r, g, b, a; 

// predefined colors 
    // rgb(0.0, 0.0, 1.0) 
    static const CColorf blue; 
}; 

它的工作原理與ccolorf.cpp定義像這樣blue

CColorf const CColorf::blue = CColorf(0.0f, 0.0f, 1.0f); 

這是我想要做的是什麼:

class CColorf 
{ 
    ... 

// predefined colors 
    // rgb(0.0, 0.0, 1.0) 
    static const CColorf blue = CColorf(0.0f, 0.0f, 1.0f); 
}; 

但它會產生一個編譯錯誤:

a static data member with an in-class initializer must have non-volatile const integral type

有沒有辦法避免這裏需要單獨的聲明和定義?

+2

聲明吧'constexpr'。 'CColof'是一種文字類型,因此應該可以工作。 – Columbo 2015-02-05 14:56:07

+0

@Columbo:不是'constexpr'應該用於表達式(或函數),而不是聲明? – 2015-02-05 14:57:22

+1

...不知道你的意思,但你聽起來很迷惑。 'constexpr'是一個decl-specifier(聲明說明符),因此只能在聲明中使用。 – Columbo 2015-02-05 14:59:02

回答

1

你不能那樣做。

錯誤消息意味着您正在編譯爲C++ 03,其中只有整型的常量靜態成員才能在其聲明中初始化;所以你不能爲任何類類型做這個。

C++ 11鬆弛的規則,但仍存在限制:

  • 類型必須是字面。你可以通過使構造函數constexpr;但
  • 類型必須是完整,和一個類不是在其定義內完成(除了內側部件定義)
  • 的構件必須不ODR使用的;也就是說,您只能使用它作爲右值表達式,並且不能取其地址或創建對其的引用。

雖然第一點可以固定,第三點只是限制你可以對會員做什麼,而不是你是否可以定義它,第二點是不可能的。您必須以通常的方式在單個翻譯單元的課程外部定義變量。

如果你想保留一切在類的定義,並可以幫助編譯時優化的價值,你可以定義一個函數,而不是一個變量

static CColorf blue() {return CColorf(0.0f, 0.0f, 1.0f);} 
3

這裏的經驗法則是,如果它是static(而不是const int),則不能使用成員變量的類內成員初始化,但也有一些例外情況(僅適用於您的情況)。

在C++ 98標準中,只能構件初始化static const int

在C++ 11標準,可以構件初始化一切除static(有例外到C++ 98標準)。

,如果你能解決這個問題您的靜態成員是constexpr

§9.4.2(2014年11月草案)

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression (5.20). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.

要多一點清楚地解釋這個片段:如果你想 嘗試用constexpr解決問題,你的類型必須是「文字」。

甲文本類型(第3.9.10):

  • 有着「平凡的」析構
  • 具有僅常量表達式構造
  • 具有僅文本類型基類和數據成員
  • 或者是aggregate type
  • 或者是void,標量(例如,int),參考或文字類型的數組

析構函數是 「平凡的」,如果:

  • 它的編譯器生成的(即你沒有定義一個)
  • 而且每個非靜態成員對象有一個平凡的析構函數

考慮到了這一切,你可以看看你的代碼,並認爲「嗯,好,我會盡一切我的構造函數constexpr,然後將static const CColorf blue更改爲static constexpr CColorf blue,我很好。「

但是,在聲明靜態時,您的類是「不完整」的。讓我們來想想以下example

class A{ 
    private: 
     A member; 
} 

A每個實例現在有A一個實例。編譯器爲A分配多少個字節?它不能說。也許,由於遞歸無限多。 A是不完整裏面有它自己的類。你也有類似的不完整問題。然而,讓我們做一個指針來代替:

class A{ 
    private: 
     A* member; 
} 

現在很容易因爲A*是一個指針類型,編譯器知道的大小。

所以,現在你認爲「好的,我只是讓static constexpr CColorf bluestatic constexpr CColorf* blue = new CColorf(0.0f, 0.0f, 1.0f);

一個指針,但你不能,因爲new經營者不得constexpr

而且你不能嘗試const因爲我們已經去了,爲什麼。

因此,也許你想重載new運營商是constexpr,但you can't do that either

所以你運氣不好。

+0

請參閱Mike Seymour對該問題的評論。你所建議的不是一個答案。 – 2015-02-05 22:06:40

+0

我的問題的答案是要麼顯示如何做我想要的代碼或3個字:「這是不可能的」。你的「答案」既不是;它說:「如果你的靜態成員是'constexpr',你可以解決這個問題,但是讓我的靜態成員'constexpr'實際上並不能解決問題。更不用說標準中那些非人類可讀的文本幾乎告訴我任何東西。 – 2015-02-06 05:41:53

+0

@VioletGiraffe:我很抱歉。有時對一個人來說很清楚的事情可能對另一個人不那麼清楚。我在答覆中增加了更多細節,希望更清楚。 – AndyG 2015-02-06 14:04:27