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

[basic.def.odr] Make example 6 much less confusing #6384

Closed
wants to merge 1 commit into from

Conversation

Eisenwave
Copy link
Contributor

@Eisenwave Eisenwave commented Jul 18, 2023

Related: #6364.

Let me start by saying that together with other members of the community whom I consider to be experts, we have spent literally hours trying to figure out the restrictions imposed by the ODR for lambda expressions.

Example 6 has greatly contributed to our confusion, for a number of reasons:

  1. The example doesn't make it clear enough in what scope the closure types are defined. This is actually key to understanding when there is an ODR violation, and when there isn't.
  2. The example is weirdly code-golfed and uses recursion. To produce an ODR violation like the example demonstrates, recursion isn't necessary, and neither is the bool parameter to the function. It took us a while to understand that the recursion has nothing to do with the ODR, and everything to do with the point of declaration of the closure type.
  3. The recursion is significantly complicating f. f is the most simple example, and actually requires no parameters.
  4. The example contains an excessively long explanation which could have been turned into explanatory comments at the location where they're relevant. This PR still needs work to trim and format everything.

@jensmaurer
Copy link
Member

I personally like the near-symmetry of the examples to show the effective differences. Since we're talking about the ODR here, it seems rather obvious that runtime execution plays no role.

If you feel a cross-reference to [expr.prim.lambda.closure] is missing, then let's add that. If you feel a comment saying "closure type defined in the scope of X" is needed, then let's add that. But putting "ill-formed" when we mean "IFNDR" is not a good direction.

@Eisenwave
Copy link
Contributor Author

Eisenwave commented Jul 19, 2023

I personally like the near-symmetry of the examples to show the effective differences. Since we're talking about the ODR here, it seems rather obvious that runtime execution plays no role.

Even if the recursion was to stay, there is a way to get recursion here with fewer parameters and thus distractions:

-inline void f(bool cond, void (*p)()) {
-  if (cond) f(false, []{});
+inline void f(void (*p)()) {
+  if (!p) f([]{}); // closure type declared inside of f()
}
-inline void g(bool cond, void (*p)() = []{}) {
-  if (cond) g(false);
+inline void g(void (*p)() = []{}) {
+  if (!p) g();    // closure type declared outside of g()
}
struct X {
-  void h(bool cond, void (*p)() = []{}) {
-    if (cond) g(false);
+  void h(void (*p)() = []{}) {
+    if (!p) h();  // closure type declared inside of X
  }
};

Personally, I think that now which version you use here, the recursion is misleading because it implies that the location of the function call to g is contributing to the ODR violation, but the location is actually irrelevant. The only thing that matters is the location of the lambda expression.

@Eisenwave Eisenwave closed this Aug 20, 2023
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

Successfully merging this pull request may close these issues.

None yet

2 participants