In this statement
cout << v1[i] << "_"[i==n-1];
the expression "_"[i==n-1]
is an expression with the string literal "_"
.
String literals have types of constant character arrays. The literal "_"
has the type const char[2]
and is represented in memory like
{ '_', '\0' }
So the expression "_"[i==n-1]
uses the subscript operator with the string literal that is with an array. The expression i == n-1
is always equal to false
that is converted to integer 0
when i
is not equal to n-1
. Otherwise it is equal to true
that is converted to 1
.
So you have either "_"[0]
that yields the character '_'
or "_"[1]
that yields the character '\0';
.
That is when i
is not equal to n-1
you in fact have
cout << v1[i] << '_';
and when i
is equal to n -1
you in fact have
cout << v1[i] << '\0';
Pay attention to that in this expression "_"[i==n-1]
the string literal is implicitly converted to pointer to its first element.
Alternatively you could write with the same effect
vector<int> v1 = {1, 2, 3, 4, 5};
int n = v1.size();
const char literal[] = "_";
for (int i = 0; i < n; i++) {
cout << v1[i] << literal[i==n-1];
}
To enlarge your knowledge bear in mind that this expression "_"[i==n-1]
you may also rewrite like ( i == n-1 )["_"]
though such an expression will only confuse readers of the code.
From the C++17 Standard (8.2.1 Subscripting)
1 A postfix expression followed by an expression in square brackets is
a postfix expression. One of the expressions shall be a glvalue of
type “array of T” or a prvalue of type “pointer to T” and the other
shall be a prvalue of unscoped enumeration or integral type. The
result is of type “T”. The type “T” shall be a completely-defined
object type.66 The expression E1[E2] is identical (by definition) to
*((E1)+(E2)) [ Note: see 8.3 and 8.7 for details of * and + and 11.3.4 for details of arrays. — end note ] , except that in the case of an
array operand, the result is an lvalue if that operand is an lvalue
and an xvalue otherwise. The expression E1 is sequenced before the
expression E2.
Pay attention to that this code snippet
vector<int> v1 = {1, 2, 3, 4, 5};
int n = v1.size();
for (int i = 0; i < n; i++) {
cout << v1[i] << "_"[i==n-1];
}
could look more clear using the range-based for loop. For example
std::vector<int> v1 = {1, 2, 3, 4, 5};
bool next = false;
for ( const auto &item : v1 )
{
if ( next ) std::cout << '_';
else next = true;
std::cout << item;
}
If the compiler supports the C++20 Standard then you can write also like
std::vector<int> v1 = {1, 2, 3, 4, 5};
for ( bool next = false; const auto &item : v1 )
{
if ( next ) std::cout << '_';
else next = true;
std::cout << item;
}
"_"[0]
and"_"[1]
. What do you get?\0
, maybe it should be"_" + (i==n-1)
, still not recommend though.