11

There was some code floating around on Reddit that defined a member-function with an explicit this object parameter defined as type int. This made me wonder how this member-function could possibly be invoked.

After doing some tests, all of the compilers (Clang, GCC, and MSVC) seem to produce different results. So, this raises the question; is the following code legal and in accordance with the C++23 standard?

struct w { constexpr bool f(this int) { return true; } };
static_assert((*&w::f)(1)); // clang ok, gcc ok, msvc nope
static_assert((*&w::f)(0)); // clang ok, gcc nope, msvc nope

Demo


GCC's error message:

<source>:3:23: error: non-constant condition for static assertion
    3 | static_assert((*&w::f)(0));
      |               ~~~~~~~~^~~
<source>:3:24: error: dereferencing a null pointer
    3 | static_assert((*&w::f)(0));
      |   

MSVC's error message:

<source>(2): error C2660: 'w::f': function does not take 1 arguments
<source>(1): note: see declaration of 'w::f'
<source>(2): note: while trying to match the argument list '(int)'
<source>(3): error C2660: 'w::f': function does not take 1 arguments
<source>(1): note: see declaration of 'w::f'
<source>(3): note: while trying to match the argument list '(int)'
17
  • 2
    I think Clang is correct, &w::f undoubtedly gives a function pointer of type bool (*)(int). Commented Jul 11, 2024 at 3:29
  • 3
    @RemyLebeau That's not true. The first parameter is this int, not int. Commented Jul 11, 2024 at 6:56
  • 2
    @user12002570 It does not seem to make this int invalid - that sentence just describes one thing the proposal allows you to do, it is just the only thing the proposal allows you to do. There is even an example that we added that demonstrates that this works. (source: my paper). Commented Jul 11, 2024 at 15:14
  • 1
    @RemyLebeau, actually &w::f here has the same type as the pointer to free function: gcc.godbolt.org/z/aG6bEPxsd Commented Jul 12, 2024 at 7:30
  • 1
    @RemyLebeau Since C++23, because of the addition of explicit object parameters, a lot of statements that originally were true for all non-static member functions are now only true for implicit object non-static member functions. Non-static member functions with explicit object parameters are somewhere between the old non-static member functions and static member functions in terms of behavior. Commented Jul 12, 2024 at 10:18

2 Answers 2

4

I also think Clang is the only compiler behaving correctly here.

this int in itself is fine. I do not see any restrictions on the type of the explicit object parameter.

&w::f is clearly defined to give a bool(*)(int) pointing to the member function.

(*&w::f)(1) and (*&w::f)(0) should then be normal calls that match the call arguments in order to the parameters of the function, so 1 or 0 will be the argument to the explicit object parameter. There won't be any problem with the call as 1 and 0 can be used as arguments for an int parameter.

So it looks to me like bugs in GCC and MSVC.

Sign up to request clarification or add additional context in comments.

23 Comments

So, w::f is a non-static member-function that, when taking its address (i.e. &w::f), gives back a function pointer of type bool(*)(int)? Which section of the C++23 standard describes this behavior?
Also, could you please quote/reference the section of the C++23 standard that determines the invocation of (*&w::f)(0) as well-defined?
This answer seems wrong. The program is ill-formed for the reason explained in my answer. Also this isn't a language-lawyered answer.
@user12002570 Obviously obj.f(10) doesn't work. The whole point of explicit object parameters is that it shall be matched against the object expression (obj), not the first argument of the call via member access expression. You didn't leave any parameter to take the 10 argument.
@Alan I do not see any reason that a w object has to be used to call the function.
|
-3

This is CWG2688 that points out that currently [expr.call] does not properly handle explicit object member functions.

Note the issue is still open.

From CWG2688:

Section: 7.6.1.3 [expr.call] Status: open Submitter: Matthew House Date: 2023-01-16

Subclause 7.6.1.3 [expr.call] paragraphs 1 and 2 do not properly handle explicit object member functions. Such a function can be called via a function pointer, via an lvalue obtained by dereferencing a function pointer, and via a class member access expression.

1 Comment

Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer, on Meta Stack Overflow, or in Stack Overflow Chat. Comments continuing discussion may be removed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.