Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is function pointer comparison in a constexpr function allowed?

Suppose I have a constexpr array of function pointers, and I want to write a constexpr function to find the array index for a specified function.

I might have code like this:

void test1(){}void test2(){}void test3(){}void test4(){}

typedef void(*func)(void);
constexpr func funcs[] = { &test1, &test2, &test3 };

constexpr int FindMatchingIdx (const func work, const int idx) {
    return (work == funcs[idx]) ? (idx) : (FindMatchingIdx(work, idx + 1));
}

constexpr unsigned int loc = FindMatchingIdx (&test1,0);

Now this code compiles on Clang and MSVC, however GCC will only compile when FindMatchingIdx is called with the first element in the array. If FindMatchingIdx is called with test1, GCC will compile the code, however if FindMatchingIdx is called with test2 or test3 GCC will fail to compile the code, giving the error message:

error: '(test1 != test2)' is not a constant expression.

If FindMatchingIdx has to recurse, GCC will fail to treat it as a constexpr function. Is this a bug in GCC? How does function pointer comparison even work inside a constexpr function? Obviously it can't be using real pointer values as those are assigned by the linker.

Working example: https://godbolt.org/g/xfv1PM

like image 913
JonathanN Avatar asked Oct 07 '16 13:10

JonathanN


People also ask

Can constexpr functions call non constexpr functions?

A call to a constexpr function produces the same result as a call to an equivalent non- constexpr function , except that a call to a constexpr function can appear in a constant expression. The main function cannot be declared with the constexpr specifier.

How do I know if a function is constexpr?

The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.

Can constexpr functions throw?

Even though try blocks and inline assembly are allowed in constexpr functions, throwing exceptions or executing the assembly is still disallowed in a constant expression.


1 Answers

I do not know if this is why gcc is complaining, but there is some arguable ambiguity in the standard about if test1 and test2 have distinct addresses, and hence compare equal.

If the standard is actually ambiguous there, then gcc is right in saying test1 != test2 is unspecified by the standard. Meanwhile, test1==test1 is specified by the standard.

The inequality of function pointers being like that has the benefit that it permits the compiler to assign two distinct functions with identical binary implementations the same address. So test1 and test2 and test3 would be distinct functions with the same address, and pointers to them would compare equal.

like image 81
Yakk - Adam Nevraumont Avatar answered Sep 27 '22 21:09

Yakk - Adam Nevraumont