How does C++ handle constexpr evaluation for non-static member function pointers on runtime objects?
The code compiles and runs, but I'm trying to understand how the expression (obj.*funcPtr)(12) can be evaluated at compile-time when obj is not declared as constexpr. I would expect that this might not meet the standard requirements for compile-time evaluation.
#include <iostream>
#include <stdexcept>
template <typename T, size_t N>
class Array
{
public:
T& operator[](size_t i)
{
if (i>=N)
{
throw std::out_of_range("Bd index!");
}
return data_[i];
}
constexpr size_t Size() const
{
return N;
}
private:
T data_[N]{};
};
class MyClass
{
public:
constexpr int myFunction(int value)
{
return value*2;
}
};
int main()
{
constexpr int (MyClass::*funcPtr)(int) = &MyClass::myFunction;
MyClass obj;
Array<int , (obj.*funcPtr)(12) > arr;
std::cout << arr.Size() << '\n';
}
1 Answer 1
The call to the function is a constant expression, because none of the items of [expr.cont]/5 disqualify it from being a constant expression. In particular you are not attempting to perform any problematic lvalue-to-rvalue conversion in the meaning of item 5.9. The only lvalue-to-rvalue conversion you perform is on value, whose lifetime started during the constant expression evaluation, and funcPtr, which is explicitly marked constexpr.
For an implementation point of view: Your function myFunction doesn't access any data member of obj. So the compiler can determine its result at compile-time from the given argument and doesn't need to care at all about the actual obj instance. Its state has no effect on the result of the function call. The result is always 24.
5 Comments
*obj part) is explicitly undefined behavior and undefined behavior disqualifies an expression from being a (core) constant expression per item [expr.const]/5.8. That dereferencing the pointer itself causes UB, even if the result is unused, has been clarified relatively recently by CWG 2823, although it was always UB to call a non-static member function on a null pointer. MSVC is wrong.constexpr from the pointer won't work, because *obj requires an lvalue-to-rvalue conversion on obj. (The built-in * can only be applied to prvalues.)nullptr is the actual culprit, not the call via the pointer. Fixing that every compiler works: godbolt.org/z/E74bYvonh Explore related questions
See similar questions with these tags.
myFunctiondoes not depends on any member ofMyClass obj. If you add dependency on such member it will fail to compile as you expected.