Question

base class's template constexpr function in derived class and got error

template <typename... Ts>
struct A
{
    template <typename C>
    constexpr auto proc() noexcept { return C{ }; }
    constexpr size_t size() noexcept { return sizeof...(Ts); }
};

template <typename... Ts>
struct B : public A<Ts...>
{
    using base_t = A<Ts...>;

    template <typename... Cs>
    constexpr auto example_prog_1() noexcept
    {
        constexpr size_t tmp = base_t::size();
        // error C2131 : its not constexpr
        return tmp + sizeof...(Cs);
    }

    template <typename... Cs>
    constexpr auto example_prog_0() noexcept
    {
        return example_prog_1<decltype(base_t::template proc<Cs>())...>();
    }
};

int main()
{
    B<int, int, int, int> obj0 { };
    constexpr size_t result0 = obj0.example_prog_0<char, char, char, char>();
}

this not work. i got error C2131 : Expression did not evaluate to a constant.

    template <typename... Cs>
    constexpr auto example_prog_1() noexcept
    {
        B dup{ };
        constexpr size_t tmp = dup.size();
        // error none  : its fine
        return tmp + sizeof...(Cs);
    }

but making copy its fine.

it also working when add 'this auto self' and using it.

could someone tell me why ? (msvc /std:c++latest)

 5  85  5
1 Jan 1970

Solution

 5

base_t::size() is this->base_t::size().

You are not allowed to dereference pointers which were made outside the constant expression (or are usable in constant expressions themselves) in a constant expression. That would be "reading the pointer's value", which the compiler does not know during at compile time.

This was the wording before P2280R4, which MSVC does not implement. That paper and this question (Why is a reference parameter in a constexpr function not a constant expression?)'s answers explain why that happened before in more detail.

When you have something that's not a pointer or a reference (e.g., the by-value this auto self, or B dup {};), this no longer applies. It's a constant expression to call the member function because you don't access the object.

Easiest solution is to make the size function static. A lot of your functions could be static.

2024-07-05
Artyer