Using constexpr method for template parameterizati

2019-09-12 09:58发布

问题:

This is a continuation of the problem I found and described here.

Say you have a struct that contains a static constexpr function and a type alias for a std::bitset (or any type you wish to template using the result of the const expression) that looks as follows:

struct ExampleStruct {
    static constexpr std::size_t Count() noexcept {
        return 3U;
    }
    using Bitset = std::bitset<Count()>;
};

Visual Studio 2015 version 14.0.25029.00 Update 2 RC highlights the Count() call in red and generates the error function call must have a constant value in a constant expression.

How might one get this to compile, or achieve similar results?

What exactly is causing the error here? Is the compiler trying to generate the type alias before the const expression function?

EDIT: The explanation for why this does not work can be found below, but since no one provided possible workarounds, here are some that I came up with:

(1) When using templates, store type alias to this type.

template<typename T>
struct ExampleStruct {
    using ThisType = ExampleStruct<T>;
    static constexpr std::size_t Count() noexcept {
        return 3U;
    }
    using Bitset = std::bitset<ThisType::Count()>;
};

(2) Move Count() function outside of the struct body.

static constexpr std::size_t Count() noexcept {
    return 3U;
}

struct ExampleStruct {
    using Bitset = std::bitset<Count()>;
};

(3) Replace constexpr method with constexpr member variable.

struct ExampleStruct {
    static constexpr std::size_t Count = 3U;
    using Bitset = std::bitset<Count>;
};

(4) Store value in constexpr member variable, and return this from Count() method.

struct ExampleStruct {
private:
    static constexpr std::size_t m_count = 3U;
public:
    static constexpr std::size_t Count() noexcept {
        return m_count;
    }
    using Bitset = std::bitset<m_count>;
};

回答1:

You might have noticed that if you move one or both lines outside of the class body, the error goes away. The problem you're running into is that class member function definitions (even inline ones) are not parsed until after the entire class definition has been parsed; therefore, when the compiler sees using Bitset = std::bitset<Count()>;, at that point Count has been declared but not yet defined, and a constexpr function that has not been defined cannot be used in a constant expression -- so you get the error you're seeing. Unfortunately, I know of no good solution or workaround for this.