2017-08-29 35 views
10

內是否有可能有這樣的事情在C++:靜態constexpr數組類本身

struct Foo 
{ 
    int x; 
    constexpr Foo(int x) : x(x) {} 

    static constexpr Foo table[] = 
    { 
     Foo(0), 
     Foo(1), 
     Foo(2), 
    }; 
}; 

我嘗試了好幾種組合,但沒有工作。如果table不是Foo類的一部分,它會起作用,但是我真的很喜歡它成爲Foo命名空間的一部分。


編輯:

我想是這樣的話,我可以訪問該表爲Foo::table原因。我有幾類這樣的命名空間,這是真的很方便,如果我可以通過寫using someNamespace::Foo導入我使用的類,然後訪問該表爲Foo::table。如果表格在課程之外,我必須通過編寫someNamespace::fooTable來訪問它。

+3

@ tobi303不,因爲表格是靜態的。 – rozina

+0

對不起,忽略了那個 – user463035818

+4

它不能工作,因爲當解析'table'時,你沒有'Foo'的完整定義。要創建一個'Foo'的實例,你需要完整的定義,編譯器必須解析整個結構直到結束。 –

回答

8

compiler error is clear here

error: invalid use of incomplete type 'struct Foo' 
     Foo(0), 
      ^
note: definition of 'struct Foo' is not complete until the closing brace 
struct Foo 
     ^~~ 

Foo被認爲是"incomplete type",直至達到其定義的右大括號。不完全類型的大小是不知道的,所以編譯器不知道有多少空間table需要。


這裏有一個解決方法:

struct FooTable 
{ 
    constexpr auto operator[](int n) const; 
}; 

struct Foo 
{ 
    int x; 
    constexpr Foo(int x) : x(x) {} 

    constexpr static FooTable table{}; 
}; 

constexpr auto FooTable::operator[](int n) const 
{ 
    constexpr Foo table[] = 
    { 
     Foo(0), 
     Foo(1), 
     Foo(2), 
    }; 

    return table[n]; 
} 

live example on wandbox

用法:

int main() 
{ 
    constexpr auto x = Foo::table[1]; 
} 

如果你不想Foo被複制,則可以將table內「詳細信息「namespace,然後返回const auto&FooTable::operator[] - example here

+0

問題是我該如何達到這樣的目的,而不是爲什麼它不起作用。編譯器錯誤足以說明原因。 – rozina

+0

@rozina:對不起,我添加了一個解決方法。 –

+0

酷解決方法:)但它沒有所需的功能。運算符[]返回一個副本,這對於編譯時間表來說並不是真正需要的。我已經添加了一些代碼給你的[** live example **](https://wandbox.org/permlink/huHhOZyOj3c8Nsh1)來顯示它。 – rozina

5

您可以使用下面的技巧,基本上出招表的模板化的包裝,這是隻有在實例化時的Foo類定義完成。

template<typename T> 
struct Wrapper 
{ 
    static constexpr T table[] = { T(0), T(1), T(2) }; 
}; 

struct Foo : public Wrapper<Foo> 
{ 
    int x; 
    constexpr Foo(int x) : x(x) {} 
}; 

不知道這是否實際上是在您的情況可以接受的解決辦法,但它是你如何能得到你的榜樣編譯和run

如果你想在Foo類中指定表項的初始值,可以延長包裝採取這些值:

template<typename T, int... Args> 
struct Wrapper 
{ 
    static constexpr T table[] = { T(Args)... }; 
}; 

struct Foo : public Wrapper<Foo, 0, 1, 2> 
{ 
    int x; 
    constexpr Foo(int x) : x(x) {} 
}; 

在這兩種情況下,你可以把所有的類都是從Wrapper派生而不需要定義更多的實例,因爲每個實例化都存在靜態的Wrapper。如果您需要輸入採取比其他int值,你也可以通過這種類型的另一個模板參數:

template<typename T, typename A, A... Args> 
struct Wrapper 
{ 
    static constexpr T table[] = { T(Args)... }; 
}; 

struct Foo : public Wrapper<Foo, int, 0, 1, 2> 
{ 
    int x; 
    constexpr Foo(int x) : x(x) {} 
}; 

struct Bar : public Wrapper<Bar, char, 'a', 'b', 'c'> 
{ 
    char x; 
    constexpr Bar(char x) : x(x) {} 
}; 

傳遞多個參數到每個構造函數是可以實現的,以及。在這種情況下,使用std::pair或其他包裝將它們分組。