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

时间:2017-08-29 07:59:20

标签: 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),
    };
};

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

修改:

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

2 个答案:

答案 0 :(得分: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

答案 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或其他一些包装器对它们进行分组。