3

Why can't I compare pointers to functions with GCC trunk?

using f_t = int(*)(int);
f_t a { nullptr }, b { nullptr };
auto c = a <=> b;

int main (){}

gives

a.cpp:4:13: error: invalid operands of types ‘f_t’ {aka ‘int (*)(int)’} and ‘f_t’ {aka ‘int (*)(int)’} to binary ‘operator<=>’
    4 | auto c = (a <=> b) == 0;
      |           ~ ^~~ ~
      |           |     |
      |           |     f_t {aka int (*)(int)}
      |           f_t {aka int (*)(int)}

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
le migou
  • 471
  • 2
  • 7
  • 2
    What are you expecting `<=>` to return when they're not equal? The address of functions is even less useful than normal addresses (varying between compilations, and can even vary from run to run if one function comes from a separate DLL/shared object loaded with ASLR); there's nothing useful to be gained from determining which is "lesser" and which is "greater". [Earlier C++ specs only defined `==`/`!=` for function pointers](https://stackoverflow.com/q/12898227/364696); I wouldn't expect them to have expanded it since. – ShadowRanger Mar 10 '20 at 15:17
  • 1
    Does this answer your question? [How to compare pointers?](https://stackoverflow.com/questions/9086372/how-to-compare-pointers) – 273K Mar 10 '20 at 15:19

1 Answers1

4

The result of using normal relational operators on function pointers is unspecified if the pointers are unequal. You can compare pointers to objects (but only meaningfully if they're pointers into the same array or structure), but relating function pointers isn't really viable.

Rather than taking the sometimes-unspecified route, C++20 simply forbids using <=> for non-object pointers.

You can test for equality between such pointers, but not their relative ordering. If you absolutely need to do this for some reason, you can cast the pointers to void*s and use std::less<> for such comparisons.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Is comparison on `void*`s even defined? – Barry Mar 10 '20 at 15:26
  • Ok but `auto d = a < b;` does compile though. – le migou Mar 10 '20 at 15:33
  • 2
    @Barry: It is for `std::less` when applied to pointers. That is, if converting a function pointer to a `void*` is a well-defined operation (which is not actually a requirement), then `std::less` must provide a well-defined total order of such pointers. – Nicol Bolas Mar 10 '20 at 15:51