Search code examples
c++identifierlocal-variablesc++26

What are the rules for _ underscore variables in C++26, and what's a name-independent declaration?


When I compile the following code, I get a warning (https://godbolt.org/z/Tx7v6jWf1):

void foo() {
    int _;
    // warning: name-independent declarations only available with
    //           '-std=c++2c' or '-std=gnu++2c' [-Wc++26-extensions]
    int _;
}

What exactly has changed about _ variables in C++26, and what's a name-indepent declaration?


Solution

  • P2169: A nice placeholder with no name has been accepted into C++26, which makes _ special in the following contexts:

    • local variables (e.g. int _)
    • local structured bindings (e.g. auto [x, _])
    • init-captures (e.g. [_ = 0] {})
    • non-static data members of other than an anonymous union (e.g. struct S { int _; })

    In such contexts, _ makes the declaration name-independent.

    _ suppresses warnings

    The standard says:

    Recommended practice: Implementations should not emit a warning that a name-independent declaration is used or unused.

    This is very similar to the recommendation for [[maybe_unused]] in [dcl.attr.unused] p4. Normally, you would get a warning for unused variables (-Wunused in GCC), but _ and [[maybe_unused]] suppress this.

    Historically, developers have used _ as a "placeholder" for unused things, so this is just standardizing existing practice.

    _ can be declared multiple times

    Furthermore, name-independent declarations cannot potentially conflict. In short, you can declare _ multiple times. However, name lookup cannot be ambiguous.

    void g() {
      int _;
      _ = 0;   // OK, and warning is not recommended
      int _;   // OK, name-independent declaration does not potentially conflict with the first _
      _ = 0;   // error: two non-function declarations in the lookup set
    }
    

    This code is taken from [basic.scope.scope] example 3.

    Note that _ also has some special interactions with using declarations. See [namespace.udecl] p10 for more details.

    Two _ are not the same entity from the linker's perspective

    Even with external linkage, two _ are not considered the same entity:

    // a.cpp
    int _ = 0;
    
    // b.cpp
    int _ = 0;
    

    When linked, this program is OK. For any name other than _, this would give you a "multiple definitions" linker error. See also [basic.link] p8.

    Compiler Support

    Only GCC 14 and Clang 18 support this feature at the time of writing. See C++26 compiler support for more.

    If you need to test for support, test for __cpp_placeholder_variables:

    #if __cpp_placeholder_variables >= 202306L