constexpr与std::array - “非类型模板参数不是常量表达式”

10

我正在尝试实现以下内容:

#include <array>
#include <cstdint>

class Class2
{
};

class Class1
{
public:
    static constexpr uint8_t GetMax() { return 5; }
    static constexpr uint8_t GetMin() { return 0; }
    static constexpr uint8_t GetCount() { return GetMax() - GetMin() + 1; }

private:
    std::array<Class2, Class1::GetCount()> m_classes;
};

但是由于错误,我无法使它正常工作:

非类型模板参数不是一个常量表达式

我正在使用Xcode 5.0。有什么想法吗?


看起来你遇到了这个 - devnull
我遇到了一个稍微不同的错误:"GetCount()在其定义之前使用"。很可能是因为Class1在成员声明中不完整。但这并不是一个答案,因为(a)我不确定,(b)我不知道如何修复它。 - Mike Seymour
@MikeSeymour 我认为你是对的,因为在 Class1 外部声明数组是有效的。但我想看看如何解决这个问题。 - Nemanja Boric
@MikeSeymour 你说的“成员声明不完整”是什么意思?就我所知,它是完整的。顺便问一下,这些方法应该是内联的吗? - BЈовић
@MikeSeymour 这些错误信息与Clang输出的类似 - http://ideone.com/kF7F8e - Mark Ingram
2
这里的评论 (https://dev59.com/BWHVa4cB1Zd3GeqPp8E0) 可能是相关的: "嗯...我认为我们之前刚讨论过这个问题:内联函数定义被视为在类定义后立即定义;所以在类定义内部它们尚不可用。请注意,您可以始终使用 static const int number = 256; 或 static constexpr int number = 256; 来代替。" - Nemanja Boric
2个回答

2

根据Nemanja Boric的回答,我将静态方法转换为静态成员。虽然这不是我想要的解决方法,但它有效。我想剩下的问题是:为什么它没有起作用?

#include <array>
#include <cstdint>

class Class2
{
};

class Class1
{
public:
    static constexpr uint8_t Max = 5;
    static constexpr uint8_t Min = 0;
    static constexpr uint8_t Count = Max - Min + 1;

private:
    std::array<Class2, Class1::Count> m_classes;
};

2
我们现在面临的问题间接地描述在3.3.7 - 类作用域中:
typedef int c;
enum { i = 1 };

class X {
    char v[i]; // error: i refers to ::i
               // but when reevaluated is X::i
    int f() { return sizeof(c); } // OK: X::c
    char c;
    enum { i = 2 };
};

这一段应该更详细地描述(9.2.2):

在类定义符的闭合}处,类被视为完全定义的对象类型(3.9)(或完整类型)。在类成员说明中,在函数体、默认参数、异常规范以及非静态数据成员的大括号或等号初始化器中(包括嵌套类中的这些内容)。否则,在其自己的类成员说明中,它被视为不完整的。

由于std::array<Class2, Class1::GetCount()>既不是函数体、默认参数、异常规范、大括号或等号初始化器,所以在那个点上,类被认为是不完整的,所以我认为是否允许这样做取决于编译器,但是根据标准不编译代码也可以。

我能想到的唯一解决方案就是你提出的方法,或者将constexpr移到另一个(可能是基础)类中。


感谢提供参考,这解决了我的疑惑。 - Mark Ingram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接