是否可以在C ++中使用这样的东西:
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
来访问它。
答案 0 :(得分:8)
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];
}
用法:
int main()
{
constexpr auto x = Foo::table[1];
}
如果您不希望复制Foo
,可以将table
置于“详细信息”namespace
内,然后从const auto&
返回FooTable::operator[]
- example here。
答案 1 :(得分:6)
您可以使用以下技巧,它基本上将表移动到模板化包装器,只有在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
或其他一些包装器对它们进行分组。