Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr with std::array - "Non-type template argument is not a constant expression" [duplicate]

I'm trying to implement the following:

#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;
};

But I can't get it to work because of the error:

Non-type template argument is not a constant expression

I'm using Xcode 5.0. Any ideas?

like image 885
Mark Ingram Avatar asked Sep 17 '13 10:09

Mark Ingram


2 Answers

The problem that we have here is indirectly described in 3.3.7 - Class scope:

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 };
};

This paragraph should describe this a little bit more (9.2.2):

A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier.Within the class member-specification, the class is regarded as complete within function bodies, default arguments, exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

As std::array<Class2, Class1::GetCount()> is neither of the functions bodies, default arguments, exception-specification, brace-or-equal initializers, at that point, class is considered incomplete, so I think it's up to the compiler to decide whenever it will allow this, or not - but not compiling the code is OK by the standard.

Only solutions that I can think of is the one you suggested, or moving constexprs into another (possible base) class.

like image 56
Nemanja Boric Avatar answered Oct 18 '22 14:10

Nemanja Boric


Following Nemanja Boric's answer, I converted the static methods into static members. This isn't the fix I wanted, but it works. I suppose the remaining question is why didn't it work?

#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;
};
like image 22
Mark Ingram Avatar answered Oct 18 '22 15:10

Mark Ingram