简体   繁体   中英

Variable definition to boolean value conversion in C++

I discovered that the below code is valid in C++98 and above:

if (int x = 7) {              // int x; if (x = 7) makes sense
  std::cout << x << '\n';     // 7 is printed
}

Question: what are the rules that govern the conversion of a variable definition to a boolean expression?

If it was like the below, it would make sense b/c the if condition is an assignment expression that would evaluate to an integer:

int x;
if (x = 7) {
  std::cout << x << '\n';
}

The result of an assignment expression is the assignment target, which in this case is x . Since bool(7) is true, the condition is true.

A common use of this feature which is much more useful is like this:

if (auto* x = get_some_pointer())
    // use x, which is known to be not null

Where the variable is declared has nothing to do with it. Following your example, this would do the same thing:

int x;
if (x = 7)
    // ...

The rules governing this piece of the grammar are in [stmt.pre]

1

 condition:\n     expression\n     attribute-specifier-seq opt decl-specifier-seq declarator brace-or-equal-initializer

4 A condition that is not an expression is a declaration ([dcl.dcl]). The declarator shall not specify a function or an array. The decl-specifier-seq shall not define a class or enumeration. If the auto type-specifier appears in the decl-specifier-seq, the type of the identifier being declared is deduced from the initializer as described in [dcl.spec.auto].

6 The value of a condition that is an initialized declaration in a statement other than a switch statement is the value of the declared variable contextually converted to bool. If that conversion is ill-formed, the program is ill-formed. The value of a condition that is an initialized declaration in a switch statement is the value of the declared variable if it has integral or enumeration type, or of that variable implicitly converted to integral or enumeration type otherwise. The value of a condition that is an expression is the value of the expression, contextually converted to bool for statements other than switch; if that conversion is ill-formed, the program is ill-formed. The value of the condition will be referred to as simply “the condition” where the usage is unambiguous.

7 If a condition can be syntactically resolved as either an expression or the declaration of a block-scope name, it is interpreted as a declaration.

8 In the decl-specifier-seq of a condition, each decl-specifier shall be either a type-specifier or constexpr .

In the above text condition is the grammatical element that appears in the grammar productions of if (condition) , while (condition) and switch (condition) . Most other mentions of condition in [stmt.stmt] deal with its value after conversion to a boolean or an integral value (in switches). And the behavior based on the value is what one would expect.

The only other thing of note that is mentioned elsewhere, is the behavior of the declaration with regard to its declarative region. For instance, in an if statement

if(auto handle = getHandle())
  handle->foo();
else
  handle->bar();

The name is available in both branches. But that is mentioned at [basic.scope.block]

3 Names declared in the init-statement, the for-range-declaration, and in the condition of if, while, for, and switch statements are local to the if, while, for, or switch statement (including the controlled statement), and shall not be redeclared in a subsequent condition of that statement nor in the outermost block (or, for the if statement, any of the outermost blocks) of the controlled statement. [ Example:

 if (int x = f()) { int x; // error: redeclaration of x } else { int x; // error: redeclaration of x }

— end example ]

Like C, C++ booleans are treated as integers with value 0 or 1. When converting from other values it will parse the boolean as false if the value is zero, every other number becomes true.

This enables easy null checks for pointers (which can also be interpreted as numbers) where a pointer with a value of 0 is the null pointer.

The result of any assignment statement is the value of the left operand after the assignment.

The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true.

So here the int x has a value of 7 becomes true.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM