| Summary: | Comparing function pointers in a constexpr function can produce an error. | ||
|---|---|---|---|
| Product: | gcc | Reporter: | Dr Hilbert Swan <yhueotnk> |
| Component: | c++ | Assignee: | Not yet assigned to anyone <unassigned> |
| Status: | RESOLVED FIXED | ||
| Severity: | normal | CC: | 0x66726565, daniel.kruegler, ppalka, webrown.cpp |
| Priority: | P3 | Keywords: | rejects-valid |
| Version: | 6.2.0 | ||
| Target Milestone: | 12.0 | ||
| See Also: | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85428 | ||
| Host: | Target: | ||
| Build: | Known to work: | ||
| Known to fail: | Last reconfirmed: | 2021-08-05 00:00:00 | |
| Bug Depends on: | 69681 | ||
| Bug Blocks: | 55004 | ||
| Attachments: |
Compiler .ii output to reproduce.
Version that compiles. |
||
|
Description
Dr Hilbert Swan
2016-10-09 15:58:06 UTC
Created attachment 39777 [details]
Version that compiles.
If a similar thing is done with ints the code would look like this:
constexpr int i[] = { 1, 2, 3 };
constexpr int FindMatchingIdx(const int w, const int idx) {
return (w == i[idx]) ? (idx) : (FindMatchingIdx(w, idx + 1));
}
constexpr unsigned int loc = FindMatchingIdx(2, 0);
int main() {
return loc;
}
Which compiles correctly. (https://godbolt.org/g/mYpxn9) I've also tried float and doubles, which are fine, but there something about function pointers that gcc doesn't like.
An alternative method using recursive template meta programming fails to compile with a very similar error: (https://godbolt.org/g/zanwsd)
void test1(){}void test2(){}
void test3(){}void test4(){}
typedef void(*Type)();
constexpr Type i[] = { &test1, &test2, &test3 };
template<Type f, int idx, bool equal>
struct FindMatchingIdx2 {
enum { value = FindMatchingIdx2<f, idx + 1, (f == i[idx + 1])>::value };
};
template<Type f, int idx>
struct FindMatchingIdx2<f, idx, true> {
enum { value = (idx) };
};
template<Type f>
struct FindMatchingIdx {
enum { flag = FindMatchingIdx2<f,0, (f == i[0])>::value };
};
int main() {
return FindMatchingIdx<test1>::flag;
}
A generous fellow offered me this workaround for the time being:
void test1(){}
void test2(){}
void test3(){}
void test4(){}
#define FUNCTION_LIST test1, test2, test3, test4
template <int N, void (&Fun)(), void (&Head)(), void (& ...Tail)()>
struct SearchFun
{
static constexpr int Idx = SearchFun<N + 1, Fun, Tail...>::Idx;
};
template <int N, void (&Fun)(), void (& ...Tail)()>
struct SearchFun<N, Fun, Fun, Tail...>
{
static constexpr int Idx = N;
};
template <void (&Fun)()>
using FindMatchingIdx = SearchFun<0, Fun, FUNCTION_LIST>;
// Tests
constexpr unsigned int loc1 = FindMatchingIdx<test1>::Idx;
static_assert(loc1 == 0, "");
constexpr unsigned int loc2 = FindMatchingIdx<test2>::Idx;
static_assert(loc2 == 1, "");
constexpr unsigned int loc3 = FindMatchingIdx<test3>::Idx;
static_assert(loc3 == 2, "");
// If the array is needed
typedef void (*func)();
func funcs[] = { FUNCTION_LIST };
// If desired the template alias can be wrapped in a macro
#define FindMatching(Fun) FindMatchingIdx<Fun>::Idx
constexpr unsigned int loc4 = FindMatching(test2);
static_assert(loc4 == 1, "");
Confirmed, I suspect this is the same problem as PR 69681. *** Bug 86607 has been marked as a duplicate of this bug. *** |