类本身内部的静态constexpr类对象数组

roz*_*ina 11 c++ arrays static constexpr

是否有可能在C++中有这样的东西:

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

    static constexpr Foo table[] =
    {
        Foo(0),
        Foo(1),
        Foo(2),
    };
};
Run Code Online (Sandbox Code Playgroud)

我尝试了几种组合,但都没有效果.如果table不是Foo类的一部分,它可以工作,但我真的希望它成为Foo命名空间的一部分.


编辑:

我想要这个的原因是我可以访问表格Foo::table.我在命名空间中有几个这样的类,如果我可以通过编写导入我正在使用的类using someNamespace::Foo然后访问该表,这非常方便Foo::table.如果表在课外,我必须始终通过写作来访问它someNamespace::fooTable.

Vit*_*meo 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
        ^~~
Run Code Online (Sandbox Code Playgroud)

Foo被认为是"不完整类型",直到达到其定义的右大括号.不完整类型的大小是未知的,因此编译器不知道需要多少空间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];
}
Run Code Online (Sandbox Code Playgroud)

wandbox上的实例

用法:

int main()
{
    constexpr auto x = Foo::table[1];
}
Run Code Online (Sandbox Code Playgroud)

如果您不想Foo复制,可以table在"详细信息"中放置namespace,然后const auto&FooTable::operator[]- 示例返回此处.


nh_*_*nh_ 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 Code Online (Sandbox Code Playgroud)

在您的情况下,不确定这是否真的是一种可接受的解决方法,但它是如何让您的示例编译和运行的.

如果要在类中指定表条目的初始化值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) {}
};
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,您都可以从中派生所有类,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) {}
};
Run Code Online (Sandbox Code Playgroud)

也可以实现向每个构造函数传递多个参数.std::pair在这种情况下,使用一个或其他包装器对它们进行分组.