Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function pointers and related types #37

Open
shaneasd opened this issue Dec 29, 2021 · 0 comments
Open

Function pointers and related types #37

shaneasd opened this issue Dec 29, 2021 · 0 comments

Comments

@shaneasd
Copy link

I couldn't find anywhere in the paper (apologies if it's because I didn't look hard enough rather than because it's not there) that talks about the type of a function which uses the new syntax. I note that in the prototype implementation pointers to functions with in, inout and out parameters have different types (https://cppx.godbolt.org/z/96WW7Gdcv) which makes a lot of sense since the requirements each place on the caller is different. It feels like this should be stated explicitly though.

In terms of expressing the types it seems like there may be a bug/limitation in the prototype in that this fails to compile https://cppx.godbolt.org/z/3TanzvYaf

void f(in int a, out int b) { b = 1; }
int main() { void (*y)(in int, out int) = &f; }

because the second parameter doesn't match because it expected out int and got out int. Naturally it's a prototype, not a fully featured implementation of the compiler but what is the intended syntax? Should this compile under the proposal? I note that auto works fine.

This question extends to function like objects as well. How should I express something like std::function<void(in int, out int)>?

I also notice that in int and int are not considered equivalent when comparing function pointer types. This code won't compile due to that incompatibility https://cppx.godbolt.org/z/fefTjd4ah. It's not clear to me whether this is the intention of the proposal.

void f(in int a){}
void unadorned(int a){}

int main() {
    auto x = &f;
    x = &unadorned;
}

The reason I'm wondering about this is I was considering the confluence of templating as an alternative to virtual functions, requiring write on inout along one code path on non-virtual functions, and requiring (or allowing) inout to be specified at the call site. Consider this code: https://cppx.godbolt.org/z/Ge8fxxe6z (which doesn't compile). In dostuff I want x to be able to modify a so I mark it as inout at the call site. In order for both f and g to be compatible with dostuff I therefore mark their parameters as inout despite the fact that one of them does not need to modify its parameter. As far as I can see this is similar to the virtual function case. We have two functions which can be used interchangeably only one of which has the effect of modifying the inout parameter. As far as I can see, in this case, I either have to

  • not specify inout at the call site so that dostuff can call either type of function
  • not require inout parameters to be written to so that g remains compatible with dostuff
  • not implement dostuff in this way (e.g. by duplicating the code in some sort of overload or with a constexpr if using traits to query whether an inout call is valid).

None of these options seems truly evil but they all have notable drawbacks. Personally if forced to choose I think I would choose the third option but whichever option is chosen it seems like it would need more discussion of the tradeoff in the relevant sections (1.3.6 and 1.3.2 respectively).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant