静态constexpr数组类本身

问题描述:

内是否有可能有这样的事情在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'的实例,你需要完整的定义,编译器必须解析整个结构直到结束。 –

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

您可以使用下面的技巧,基本上出招表的模板化的包装,这是只有在实例化时的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或其他包装将它们分组。