Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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.
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading