4
votes
struct A{
    int a;
};
struct B{
    int b;
};
auto&& [x] = A{};  //#1
auto&& [x] = B{};  //#2
int main(){
}

In this example, all compilers give an error that the x at #2 conflicts with that introduced at #1. However, IIUC, there's no rule in the post-C++20 working draft standard which can interpret what's the reason.

First, in my opinion, the declaration at #2 and the declaration at #1 declare the same entity. They correspond due to: basic.scope#scope-3

Two declarations correspond if they (re)introduce the same name, both declare constructors, or both declare destructors, unless

[...]

They declare the same entity per basic.link#8

Two declarations of entities declare the same entity if, considering declarations of unnamed types to introduce their names for linkage purposes, if any ([dcl.typedef], [dcl.enum]), they correspond ([basic.scope.scope]), have the same target scope that is not a function or template parameter scope, and either

  • they appear in the same translation unit, or
  • [...]

So, as far as now, they declare the same entity and they shouldn't be considered as potentially conflict per basic.scope#scope-4

Two declarations potentially conflict if they correspond and cause their shared name to denote different entities([basic.link]). The program is ill-formed if, in any scope, a name is bound to two declarations that potentially conflict and one precedes the other ([basic.lookup]).

Since they denote the same entity, as aforementioned, they do not potentially conflict.

They still do not violate this rule:
basic.link#11

For any two declarations of an entity E:

  • If one declares E to be a variable or function, the other shall declare E as one of the same type.
  • [...]

Since structured bindings are not mentioned in this list, they do not violate this rule. Similar, they do not violate One-definition rule

No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, template, default argument for a parameter (for a function in a given scope), or default template argument.

At least, according to what the relevant rules say, the two declarations in this example shouldn't result in any program ill-formed. If I don't miss some other rules, Can it be considered as vague in the standard which cannot interpret why two structured binding declarations conflict with each other in this case? This case is more underspecified in the N4861

2
How on earth can two variables initialised with different expressions, with different types even, be considered "the same entity"??Asteroids With Wings
@jackX: No, but it does introduce a name, and that name denotes an entity. Why do you believe that those names denote the same entity?Nicol Bolas
@jackX: No, you have to explain how that rule says that they're the same entity. I don't see that anywhere; you merely declare that the bold text says that they're the same, and it doesn't.Nicol Bolas
@jackX: Can you point out where that is in an actual standard, not a work-in-progress? C++23 is not finished and may not at any particular moment be entirely consistent with itself.Nicol Bolas
@jackX: I interpret it by not bothering. Name scoping rules are a jumbled, nightmare mess of nonsense, and it's best to just do what your compiler tells you and/or avoid reusing names in places where it would be at all reasonable for them to conflict. Knowing too much about abstract esoterica of C++ naming only makes it easier to write code that makes no sense to the reader. That is, whether that code "works" or not is irrelevant because you shouldn't write it to begin with.Nicol Bolas

2 Answers

4
votes

This is just a missing case in [basic.link]/11: that if one (of the two declarations) declares a structured binding, the program is ill-formed. (One could alternatively merely require that the other also declare a structured binding and then extend the list in [basic.def.odr]/1, but that’s more complicated and suggests that it might be possible to redefine it in another translation unit.)

1
votes

You are citing text from a working draft of a post-C++20 version of the language. As such, the behavior it describes is not likely implemented by any compiler currently existing. As it is a working draft, it likely contains a number of language defects and/or bugs, so trying to learn from it is not a productive activity.

All of the "correspond" language you cite is adopted from P1787, which is not part of any C++ standard actual compilers implement. As such, compilers are providing you with the C++20 functionality, and under those rules, these clearly conflict.

There may be some defective wording in P1787, but that's expected with complex proposals and working drafts of a standard. File a defect report on it.