Возможно ли сравнение указателей на функции в функции constexpr?

Предположим, что у меня есть массив constexpr указателей на функции, и я хочу написать функцию constexpr, чтобы найти индекс массива для указанной функции.

У меня может быть такой код:

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);

Теперь этот код компилируется на Clang и MSVC, однако GCC будет компилироваться только при вызове FindMatchingIdx с первым элементом в массиве. Если FindMatchingIdx вызывается с помощью test1, GCC будет компилировать код, однако если FindMatchingIdx вызывается с помощью test2 или test3, GCC не сможет скомпилировать код, указав сообщение об ошибке:

error: '(test1!= test2)' не является постоянным выражением.

Если FindMatchingIdx должен возвращаться, GCC не сможет обработать его как функцию constexpr. Это ошибка в GCC? Как сравнение указателя функции даже работает внутри функции constexpr? Очевидно, что он не может использовать реальные значения указателя, поскольку они назначаются компоновщиком.

Рабочий пример: https://godbolt.org/g/xfv1PM

Ответ 1

Я не знаю, является ли это причиной того, что gcc жалуется, но есть некоторая сомнительная двусмысленность в стандарте о том, имеют ли test1 и test2 разные адреса, и, следовательно, сравните равные.

Если стандарт там действительно двусмыслен, то gcc прав, говоря, что test1 != test2 не указывается стандартом. Между тем, test1==test1 указывается стандартом.

Неправильное использование указателей функций имеет то преимущество, что позволяет компилятору назначать две разные функции с идентичными бинарными реализациями одного и того же адреса. Таким образом, test1 и test2 и test3 будут различными функциями с одинаковым адресом, а указатели на них будут сравнивать равные.