Владимир Н
Владимир Н

Reputation: 3

error: 'this' is not a constant expression

I have constexpr object constructor with constexpr methods.

// My SparseArray implementation

#include <cstdint>
#include <iostream>
#include <utility>

template<typename T, uint64_t size>
class SparseArray 
{
    public:
    using ElementType = T;

    template<typename... Args>
    constexpr SparseArray(Args&&... args) 
    : values{args...} {
        std::cout << "Args ctor." << '\n';
    }

    template<uint8_t Index>
    constexpr ElementType get() const {
        // some logic
        return T();
    }

    constexpr auto someMethod() {
        get<0>();                                            // <--------- works fine
        auto seq  = std::integer_sequence<ElementType, 0>{}; // <--------- works fine
        auto seq2 = std::integer_sequence<ElementType, get<0>()>{}; // <-- error
    }

    ElementType values[size];  
};

int main ()
{
    SparseArray<int, 3> array(1, 2, 3);
    array.someMethod();

    return 0 ;
}

Run code

But I really need to use method in such compile-time context. I'm going to sum two constexpr objects in compile-time, so I need to get data of both thanks to get method.

=======Edited=====

After @chris answer I understood that I missed one thing. Actually get method looks like this:

    template<uint8_t Index>
    constexpr ElementType get() const {
        if(/*some logic*/)
            return values[/*some logic*/];
        else
            return T();
    }

So, the code deals with data member of the object.

Upvotes: 0

Views: 3858

Answers (1)

Qaz
Qaz

Reputation: 61910

constexpr functions have to be usable at compile-time and runtime. You're calling a non-static member function, so it needs to work regardless of whether the class object is known at compile-time. If you require the object to be known at compile-time, the function no longer works at runtime.

The easiest way around this is to use a function that doesn't depend on the unused class object:

template<uint8_t Index>
static constexpr ElementType get() {
    // some logic
    return T();
}

If that isn't an option because you are using the class object, then you need to ensure that object is constexpr to use it:

constexpr SparseArray<int, 3> array(1, 2, 3);
auto seq2 = std::integer_sequence<int, array.get<0>()>{};

Regardless of where you use get, the only way the result is going to be usable as a compile-time value is if all parameters, including the object, are compile-time values.

EWG has accepted constexpr! to force compile-time evaluation of a function, but it wouldn't make your original example compile until used with a constexpr SparseArray object.

Upvotes: 3

Related Questions