ERR: Constexpr variable must be initialized by a constant expression, but it is

Advertisements

I am using clangd as LSP, with C++20 and I have stuck with such a problem. I have no idea why I cannot initialize a constexpr array with a constexpr function. Inserting a direct values works but I would like to understand why my "automatic" solution doesn’t work.

Error returned by clangd LSP is probably because of a second issue, but I don’t know why defined function is not seen as defined.

IpRange.h

class IpRange {
    inline static constexpr uint32_t getMaskValue(const ushort shortForm) {
        return 2^(32 - shortForm) - 1;
    }

    template <typename T>
    inline static constexpr T getMaskValues() {
        auto masks = T();
        for (ushort i = 0; i < 33 ; i++) {
            masks[i] = getMaskValue(i);
        }
        return masks;
    }

    static constexpr std::array<uint32_t, 33> maskValues { getMaskValues<std::array<uint32_t, 33>>() };

    //Returns clangd error: Constexpr variable 'maskValues' must be initialized by a constant expression
    //Returns compilation error: constexpr T IpRange::getMaskValues() [with T = std::array<unsigned int, 33>]’ used before its definition

    static constexpr std::array<uint32_t, 33> maskValues { 1, 2, 3 };
    //Works fine...
}

Solution. Moving Masks-stuff to another class.

#define MASK_VAL_NUM 33

class MaskValues {
    typedef std::array<uint32_t, MASK_VAL_NUM> MaskValA;

    inline static constexpr uint32_t getMaskValue(const ushort shortForm) {
        return 2^(32 - shortForm) - 1;
    }

    inline static constexpr MaskValA getMaskValues() {
        auto masks = MaskValA();
        for (ushort i = 0; i < MASK_VAL_NUM ; i++) {
            masks[i] = getMaskValue(i);
        }
        return masks;
    }

    const std::array<uint32_t, MASK_VAL_NUM> maskValues;

public:
    constexpr MaskValues(): maskValues{getMaskValues()} {
    }

    const uint32_t& operator[](std::size_t idx) const {
        return this->maskValues[idx];
    }
};


class IpRange {
    static constexpr MaskValues maskValues {};
}

>Solution :

G++ gives a better error message for this one than Clang:

main.cpp:19:99: error: ‘static constexpr T IpRange::getMaskValues() [with T = std::array<unsigned int, 33>]’ used before its definition
   19 | es<std::array<uint32_t, 33>>();
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~

The problem is that you’re calling the getMaskValues while the definition of the class is not yet complete and you can’t call a member function of a class that is in this state.

Even if you remove the templates, you will still get this error message from GCC:

main.cpp:18:73: error: ‘static constexpr std::array<unsigned int, 33> IpRange::getMaskValues()’ called in a constant expression before its definition is complete
   18 |     static constexpr std::array<uint32_t, 33> maskValues = getMaskValues();
      |                                                            ~~~~~~~~~~~~~^~

Essentially you can’t call IpRange::getMaskValues while IpRange is still not complete.

To fix this:

  • You can move getMaskValues (and whatever it needs) into a separate class (moving into sub-classes won’t work) or define them globally
  • You can make the IpRange class a templated class.

Leave a ReplyCancel reply