Probably like many, I typed this typo
int a = 0;
cout << a < " "; //note the '<'
However, the MSVC++ compiler threw just a warning
warning C4552: '<' : operator has no effect; expected operator with
side-effect
though I expected a compilation error. Is it indeed standard complaint code? Does any implicit type conversion or overloading happen which make the code valid? I am also confused whether < operator is comparing the string " " with an integer a or with the result of cout << a
A related SO post is here.
The << operator has a higher precedence than <, so this is parsed as
(cout << a) < " ";
You are not really comparing a string with an integer. Instead, you are comparing the return value of ostream::operator<<, which is std::cout itself, to the string literal. This isn't legal (in the sense that is has an unspecified result, and it is not meaningful) either, clang warns:
warning: result of comparison against a string literal is unspecified
The reason why it compiles is that up until C++11, std::ostream can be implicitly converted to void *. Also, the string literal of type const char[2] decays into a pointer of type const char *. So, the < operator now takes two pointers, which is permitted, although its result is not specified, because the two pointers don't point to the same object.
Actually, since it is (cout << a) < " ", we're comparing an ostream with " ". The ostream class has an operator to convert it to void *. You can compare a void * with a const char * without cast, so the compiler is happily doing that, then realizing that you are not using the result of the comparison, and issues the warning.
One of those quirky things in C++.
It is down to operator precedence
i.e.
The line equates to (cout << a) < " "; - Hence the <" " does nothing!
EDIT
This bit returns an object (cout << a) returns an object of type ostream where it does not have an overloaded operator <, so either the compiler gives up (C++11) or scratches its head amd has a bash at the integer operator (i.e. pointers etc).
Related
I had a copy/paste error in my code and ended up with a line that looked like:
myString = otherString; + "?" + anotherString;
The code after the first semicolon wasn't issuing any errors or warnings. Using an online compiler to double check my environment, I created this quick example that also compiles and runs:
int main()
{
std::string sText("Hello World");
std::string sMore(" again");
+ "???" + sText + sMore; //No warning, no error
cout << sText; //output "Hello World" as expected
+ 4; //Warning has no effect
+ sMore; //error: no match for ‘operator+’ (operand type is ‘std::string {aka std::basic_string}’)
return 0;
}
So what is the beginning + doing?
Literal strings (like e.g. "???") are really arrays of characters. And as all other arrays they decay to pointers to themselves. And this is what happens here, the expression + "???" applies the unary + operator on the pointer to the first element of the string.
This results in another pointer (to a character) that is equal to the first, and which can then be used to add to std::string objects.
The same thing happens for other literals, like numbers, which is why +4 is valid as well.
But there's no unary + operator defined for std::string which is why you get an error for +sMore.
Firstly, string literal is an array of characters. When you pass an array as operand to unary operator +, the array is implicitly converted to a pointer to first element (which is of type const char). This implicit conversion is called decaying.
The result of unary operator + is the operand after the conversion i.e. the pointer to the first element of the string literal in this case.
The following binary operator + invokes the overloaded operator that takes a pointer to a character as one operand, and a std::string object as the other.
For integers, operator + behaves the same, except instead of array-to-pointer decay, there is integral promotion. int is not promoted, but all types smaller than int are. For std::string, there is no overload for unary +, hence the error.
And I assume that there is no warning on that line because calling operator+ is "having an effect" even tho the value isn't stored.
Lack of effect is only a reason to warn about if the result of the operation is discarded. In the string case, the result is used as an operand of the binary operator, so there is no reason to warn about lack of effect.
Now, the result of the binary operation is discraded, and has no effect either, but it is practically impossible for the compiler to analyse all possible code paths for "effects", and it doesn't attempt to do so. The compiler is kind enough to check for primitive operations on pointers, but it probably won't bother analysing function calls (operator overloads for classes are functions).
This question already has answers here:
Conditional operator used in cout statement
(3 answers)
Closed 3 years ago.
I was solving a problem about movement of a bishop on a chessboard. At one point of my code, I had the following statement:
std::cout << (abs(c2-c1) == abs(r2-r1)) ? 1 : 2 << std::endl;
This generates the following error:
error: invalid operands of types 'int' and '<unresolved overloaded function type>' to binary 'operator<<'
However, I instantaneously fixed this error by including an additional variable in my code:
int steps = (abs(c2-c1) == abs(r2-r1)) ? 1 : 2;
std::cout << steps << std::endl;
How does the ternary operator work, and how is its return type determined (as the compiler called it <unresolved overloaded function type>)?
This has nothing to do with how the return type is deduced and everything to do with operator precedence. When you have
std::cout << (abs(c2-c1) == abs(r2-r1)) ? 1 : 2 << std::endl;
it isn't
std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;
because ?: has lower precedence than <<. That means what you actually have is
(std::cout << (abs(c2-c1) == abs(r2-r1))) ? 1 : (2 << std::endl);
and this is why you get an error about an <unresolved overloaded function type>. Just use parentheses like
std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;
and you'll be okay.
You have to put parentheses around a ternary operation:
std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;
If not the the << operator goes to the 2 and it gives an error because it doesn't have such overloaded function.
This happens because the bitwise left shift operator (<<) has a higher precedence than the ternary operator. You can see the full list of operators and their precedence in this page of the C++ reference.
Due to operator precedence, that line is treated as:
(std::cout << (abs(c2-c1) == abs(r2-r1))) ? 1 : (2 << std::endl);
Change it to
std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;
// ^----------------------------------^
// Surrounding parentheses
It's easy to see the mistake when the parsing order is visualized:
std::cout << (abs(c2-c1) == abs(r2-r1)) ? 1 : 2 << std::endl;
\_______/ <--- #1
\________________________/ V \~~~~error~~~/ <--- #2
\_____________________________________________/ <--- #3
\__________________________________________________________/ <--- #4
\___________________________________________________________/ <--- #5
The literal answer to the question you asked is the algorithm in the [expr.cond] secton of the C++ language standard.
The basic rule “determined whether an implicit conversion sequence can be formed from the second operand to the target type determined for the third operand, and vice versa.” If there isn’t one possible conversion, or there is more than one, it’s a syntax error, but there are several special cases (which don’t apply here):
If both are arithmetic or enum types, you get the same kind of implicit conversion for p ? a : b that determines the type of an expression such as a + b or a * b.
One of the targets may be a throw expression, and is treated as having the type of the other.
If one of the targets is a bitfield, so is the type of the conditional expression
Pointers with different qualifiers (such as const and volatile) have their qualifiers unified.
The result is a glvalue if the targets are glvalues of the same type, and a prvalue otherwise.
When in doubt, you can always explicitly cast one or both of the operands so that they have the same type.
Your actual problem here is operator precedence, as the accepted answer explains. That is, the compiler parses the third operand as 2 << std::endl, rather than 2.
According to cppreference:
When parsing an expression, an operator which is listed on some row of the table above with a precedence will be bound tighter (as if by parentheses) to its arguments than any operator that is listed on a row further below it with a lower precedence. For example, the expressions std::cout << a & b and *p++ are parsed as (std::cout << a) & b and *(p++), and not as std::cout << (a & b) or (*p)++.
Operators that have the same precedence are bound to their arguments in the direction of their associativity. For example, the expression a = b = c is parsed as a = (b = c), and not as (a = b) = c because of right-to-left associativity of assignment, but a + b - c is parsed (a + b) - c and not a + (b - c) because of left-to-right associativity of addition and subtraction.
Associativity specification is redundant for unary operators and is only shown for completeness: unary prefix operators always associate right-to-left (delete ++*p is delete (++(*p))) and unary postfix operators always associate left-to-right (a[1][2]++ is ((a[1])[2])++). Note that the associativity is meaningful for member access operators, even though they are grouped with unary postfix operators: a.b++ is parsed (a.b)++ and not a.(b++).
Operator precedence is unaffected by operator overloading. For example, std::cout << a ? b : c; parses as (std::cout << a) ? b : c; because the precedence of arithmetic left shift is higher than the conditional operator.
This question already has answers here:
What is the purpose of unary plus operator on char array?
(2 answers)
Closed 4 years ago.
I was reading this answer today and noticed a plus sign in front of the char arrays, but don't know what does it mean.
Given the compilation error when I remove it I can guess it is something to help the compiler to infer the return type, but I don't know how it works.
Test code (also here):
#include <iostream>
using namespace std;
auto& operator<<(std::ostream& os, const char (&s)[2]) {
return os << (*s == ' ' && !s[1] ? +"\n" : +s);
}
int main() {
cout << "Hello" << " " << "world" << " " << 2018;
return 0;
}
When removing the plus signs (sample) it doesn't compile:
main.cpp: In function 'auto& operator<<(std::ostream&, const char (&)[2])':
main.cpp:6:48: error: use of 'auto& operator<<(std::ostream&, const char (&)[2])' before deduction of 'auto'
return os << (*s == ' ' && !s[1] ? "\n" : s);
^
main.cpp: In function 'int main()':
main.cpp:10:24: error: use of 'auto& operator<<(std::ostream&, const char (&)[2])' before deduction of 'auto'
cout << "Hello" << " " << "world" << " " << 2018;
^~~
Built-in unary operator+ could take pointer type (but not array type) as its operand, so using it on an array causes array-to-pointer decay, then +"\n" and +s would return const char *.
On the other hand, if you remove the usage of operator+, you'll try to pass the array with type const char[2] to os, which leads to recursive invocation, as the error message tried to tell you.
For the built-in operator, expression must have arithmetic, unscoped enumeration, or pointer type. Integral promotion is performed on the operand if it has integral or unscoped enumeration type and determines the type of the result.
The built-in unary plus operator returns the value of its operand. The only situation where it is not a no-op is when the operand has integral type or unscoped enumeration type, which is changed by integral promotion, e.g, it converts char to int or if the operand is subject to lvalue-to-rvalue, array-to-pointer, or function-to-pointer conversion.
It's unary plus. The built-in operator can only be applied to numerical types and pointers. All it does is cause an implicit conversion if one is required, and return the operand unchanged.
Since s is a reference to an array, it cannot have + applied before it decays to a pointer, so the operator forces the array-to-pointer conversion to occur.
The reason it must be done is that "\n" is itself a const array of two characters. Since the conditional expression has the common type of its second and third operand, it would have the type char const(&)[2] unless one operand was coerced into a pointer beforehand.
And you can guess which overload of operator<< will be called for char const(&)[2] can you not?
I just tried this code:
int i = 33;
int * pi = &i;
cout << "i: " << *pi << endl;
cout << "i: " << pi[0] << endl;
Both lines return the same thing.
Essentially, if I get index zero of any pointer, I'll get the value of the correct type at the location of the pointer. Isn't that the same thing as dereferencing?
Every time a pointer is dereferenced in C++, wouldn't getting index zero also work? I'm not suggesting anyone should actually do that, but I think it would work. Wouldn't it?
Ignoring overloaded operators, there's one case there is a difference, and that's array rvalues post-DR1213:
using arr = int[2];
arr&& f();
int&& b = *f(); // error, *f() is an lvalue, doesn't bind to int&&
int&& c = f()[0]; // OK, subscript applied to array rvalue results in an xvalue
I don't know of any compiler that implements that resolution, though. But it should be implemented eventually.
Assuming no operator overloading, they are nearly the same.
[C] 6.5.2.1 Array subscripting:
E1[E2] is identical to (*((E1)+(E2)))
[C++] 5.2.1 Subscripting:
The expression E1[E2] is identical (by definition) to *((E1)+(E2)) ... , except that in the case of an array operand, the result is an
lvalue if that operand is an lvalue and an xvalue otherwise.
See the great answer of #T.C regarding the last part.
For pointers, they should give the same result.
The only time that they could differ is if you are applying them on a user-defined type that overloads operator*() and operator[](int) differently (or one and not the other, in which case you would get a compile error).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Operator overloading
I'm making a long awaited return to C++ and there's some basic notation that doesn't really seem to be that prominent in other languages.
If you look at this line of code
cout << "firstvalue is " << firstvalue << endl;
I realise what this does. It write's "firstvalue is x" to the console. x being the value of firstvalue. However, I do not know anything about the "<<" or ">>" double angled brackets. I haven't been able to research them or what they do as I don't know the formal name for them.
My question is, what actually happens (step by step) in the above statement? And what are these "<<" for? I think I understand that cout is a standard library function for writing to the console. However I'm used to either objective-c or dot notation. I do not see what object this "cout" function is a member of.
I can understand printf a little more easily, as at least it provides braces for the arguments. e.g. printf("your string here").
C++ allows operator overloading. That means a user-defined type can define its own behavior on built-in operators. In this case the operators are called: left shift or right shift operators. Those operators have been traditionally been used for bit-shifting, but the standard library repurposes them to symbolize streaming operations.
You can find a list of the available operators in C and C++ here.
In your case you are streaming a string literal and a value of some type into std::cout, which is an object of type std::basic_ostream.
Step-by-Step
After precedence rules have been applied your code looks like this:
((cout << "foobar") << x) << endl;
The compiler will basically transform the object << object expressions into function calls.
operator<<(operator<<(operator<<(cout, "foobar"), x), endl);
Then it will figure out which overload to call. (This is really
tricky. For now it should be sufficient to believe that it simply
looks for an overload of operator<< with matching arguments).
Most of the built-in overloads for basic_ostream are here and here.
The << operator is the "arithmetic left shift" in C++. For example:
3 << 2
evaluates to 12. The reason is that the binary representation of 3 is
00000011
shifting it twice to the left you get
00001100
and the numeric value of the result is 12.
What it has to do this with output? Nothing at all, actually. However in C++ you can redefine the meaning of operators thanks to overloading. The C++ standard library decided to redefine the meaning of the left-shift operator as sort of a "send-to-stream".
So what happens is that
std::cout << "whatever"
returns as value std::cout, but as side effect it outputs the string "whatever".
The operator was chosen because it had a reasonable precedence (overloading cannot change precedence, and you cannot define new operators) and the shape makes it appear somewhat "natural". Note however that the left-shift operator is just a normal operator and for example there is no guarantee about order of evaluation:
std::cout << f() << g() << h();
here the output will be the result of calling f(), followed by the result of calling g() and followed by the result of calling h()... but the functions themselves may be are called in a different order and for example h() could be called first!
So in a sense the "sequence look" of the operator is misleading, because it's about the sequence of output, but not about the sequence of evaluation.
C++17 update
In C++17 this design bug was fixed by special casing << operator to ensure left-to-right evaluation. After C++17 in the expression std::cout << f() << g(); f must be called before g.
The << is an operator, the same way + is an operator and * is an operator. In the way the following are equivalent expressions:
5 + 3 + 2
((5 + 3) + 2)
So are the next two:
std::cout << "Hello" << std::endl
((std::cout << "Hello") << std::endl)
It's just an operator with two operands. For the fundamental types, the << and >> operators are actually known as the left and right shift operators. They perform bitwise shifting. For example, 5 << 1 will shift all the bits in 5 (0101) left one place, to get 10 (1010).
However, as with most other operators, you can overload the shift operators. In the case of the input/output library, the shift operators are overloaded to provide a natural syntax for input and output to a stream. That's because the directionality of the << and >> tokens look like something is flowing one way or the other. With these I/O classes, these operator overloads return a reference to the stream you're performing the operator on so that they can be chained together.
You can overload the shift operators for a particular class by either providing a member function operator<< or operator>> that takes one argument (the operand to the right of the operator). Alternatively, you can provide non-member function with the same names that take two arguments, the two operands of the operator respectively.
They're referred to as stream insertion (or extraction, in the case of istream >>), and are actually a semantic overload of the left-shift and right-shift operators.
So, this:
int x = 1 << 1;
is a bit shift, but this:
std::cout << x;
is a stream insertion. You can write it out explicitly as:
operator <<(std::cout, x);
and get exactly the same result. The conventional format of stream insertion operators (they can be overloaded for user-defined types, so it's not unusual to write your own) is
std::ostream& operator <<(std::ostream&, T value);
The output stream is returned (by reference) so you can chain calls: your example translates as:
operator<< (
operator<< (
operator<<(std::cout, "firstvalue"),
firstvalue
),
std::endl
);
Oh, and ... std::cout (and std::cerr etc.) are not functions: they're global objects. The function here is the overloaded << operator. Think of them as FILE *stdout, *stderr equivalents.
There are some advantages of C++ iostreams over printf et. al:
type-safety: you can't mistakenly print an integer with "%f" and get garbage, because overload resolution automatically selects the std::ostream& operator<<(std::ostream&, double) function at compile time
support for user-defined types: you can write a stream insertion operator for your whizzy new class, and it will just work, everywhere
stream abstraction: you can use the same overloads (so you only write them once) to format to stdout and stderr (cout/cerr), and files (std::ofstream) and strings (std::ostringstream). There's no need to handle printf/fprintf/snprintf separately.
There are also some disadvantages:
performance: there is some penalty to all that abstraction, and the generality of the locale system which is configured at runtime
verbosity: at least for primitive types already supported by printf, the format strings are much terser and more expressive
It's syntactic sugar for the following:
// Let the function 'print' be a renaming of 'operator<<'
// with T being the type of the object you want to print.
std::ostream& print(std::ostream&, const T&);
// 1) Print "first value is" and then return the stream you
// to which to just printed (ie. cout). 2) Use the returned
// stream to chain function calls and print 'firstValue'.
print(print(std::cout, "first value is"), firstValue);