From this question & the answers - What is the correct answer for cout << c++ << c;?
I get that
std::cout<<c++<<c;
is evaluated as:
std::operator<<(std::operator<<(std::cout, c++), c);
so the undefined behavior comes from the fact that either of the two parameters could be evaluated first. So far so good.
But why std::operator <<? Why isn't std::ostream::operator << called? And if it is, wouldn't it translate to
(ofstream::operator<<(c++)) << c;
|
returns ofstream&
What's the difference between this and method chaining:
struct A
{
A& foo();
void goo();
};
//...
A a;
a.foo().goo();
?
std::ostream provides operator<< as overloaded member operators, but other headers (e.g. <string>) provide free operators; so whether << is a member operator or a free function depends on the RHS type.
However, it doesn't matter either way. Let's rename << as foo and cout as bar:
foo(foo(bar, c++), c);
bar.foo(c++).foo(c);
In both cases behaviour is undefined because there is no requirement on the implementation to evaluate the arguments to either call to foo in any particular order. The important consideration is that per Annex C, a chained method call does not constitute more than one full-expression; if the compiler sees
foo.bar(<some-complex-expression>).baz(<another-complex-expression>);
it is free to apply CSE and reordering to the arguments to bar and to baz; indeed examination of side effects may show that the arguments to baz are evaluated before those to bar.
struct A { A &foo(int) { return *this; } };
#include <cstdio>
int main() { A().foo(printf("hello\n")).foo(printf("bye\n")); }
My compiler (gcc 4.1.2) generates a program which prints bye\nhello\n.
Related
It was my understanding that overloaded operators are translated by the compiler into method calls, for example :
stream << "test";
Is the same as:
stream.operator<<("test");
If that is indeed the case, then why does this lead into a compilation error:
#include <iostream>
#include <iomanip>
#include <ctime>
int main()
{
std::ostream s {std::cout.rdbuf()};
auto t = std::time(nullptr);
auto tm = *std::localtime(&t);
s.operator<<(std::put_time(&tm, "%H:%M:%S"));//doesn't work
return 0;
}
While changing the doesn't work line to:
s << std::put_time(&tm, "%H:%M:%S");
Makes the code compile.
Both GCC and MSVC 2017 on C++14 seem to produce an error. Is this a compiler bug or are those two statements not equal?
Here's your code, but reduced:
struct X { friend void operator+(X, X); };
int main() {
X var;
var + var; // ok
var.operator+(var); // fail
}
The thing is, by explicitly calling the operator<<, you are relying on the fact that it is indeed an operator of the class (like T& T::operator<<(const U&);) and not an operator defined outside the class (because if the operator is not a member, you can't write var.operator<<(/*...*/)).
If you write var << something, then in addition to the operators defined in the class, lookup (called ADL) finds the operators defined outside of the class as well.
The operator can be defined outside of the class, because std::put_time's return type is specified to ([ext.manip]:
An object of unspecified type such that if out is an object of type basic_ostream<charT, traits> then the expression out << put_time(tmb, fmt) behaves as if it called f(out, tmb, fmt), where the function f is defined as: [...]
Because the requirement is of the form var << var2, nothing prohibits standard library implementations to define it outside of the class so that it is found using ADL.
Consider following code:
#include <iostream>
void foo(int m);
void foo(int &k);
int main()
{
foo(5); // ok, because there is no ambiguity
int m = 5;
//foo(m); // compile-time error, because of ambiguity
foo(m + 0); // ok, because it's an expression of type int and not object's lvalue
}
void foo(int m)
{
std::cout << "by value\n";
}
void foo(int &k)
{
std::cout << "by reference\n";
}
I understand that it introduces ambiguity for foo(m), but is this allowed, when expression is of type int (or another that can be converted to int)?
I have tried to find some standard reference on this, yet with no luck.
Disclaimer: Note that it's not duplicate of Function Overloading Based on Value vs. Const Reference. The const references are different as they can be assigned with rvalues, as opposite to "ordinary", non-const references.
13.1 [over.load] is pretty clear (apart from a multi-page note) about which functions cannot be overloaded in the same scope.
Your case is not listed there, and you can declare those overloads, you just can't necessarily use them easily. You could call the lvalue one like so:
void (*f)(int&) = foo;
f(m);
This avoids the ambiguity that happens when you call foo(m).
Aside: another way to write foo(m + 0) is simply foo(+m), the unary + operator converts the lvalue to an rvalue, so the foo(int) overload is called.
Yes, it is allowed.
There is no rule to prevent this overload.
[C++14: 13.1/1]: Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. [..]
[C++14: 13.1/2]: (blah blah lots of exceptions not including any for this case)
It would be extremely limiting for the language to prohibit function overloads that may be ambiguous in certain scenarios with certain calls, and for no good reason I might add!
Here is the source code similar to the surrogate call functions that I read on the post "Hidden features in C++"
The only part that confuses me is those operator overloaded functions.
What kind of operators are they? (They certainly don't seem like ordinary operator()'s, and why is it returning a function pointer even though there is no return type specified?
Thanks!
template <typename Fcn1, typename Fcn2>
class Surrogate {
public:
Surrogate(Fcn1 *f1, Fcn2 *f2) : f1_(f1), f2_(f2) {}
// Overloaded operators.
// But what does this do? What kind of operators are they?
operator Fcn1*() { return f1_; }
operator Fcn2*() { return f2_; }
private:
Fcn1 *f1_;
Fcn2 *f2_;
};
void foo (int i)
{
std::cout << "foo: " << i << std::endl;
}
void bar (double i)
{
std::cout << "bar: " << i << std::endl;
}
int main ()
{
Surrogate<void(int), void(double)> callable(foo, bar);
callable(10); // calls foo
callable(10.1); // calls bar
return 0;
}
They are implicit type conversion operators to Fcn1* and Fcn2*.
In the expression "callable(10)" callable is converted by the compiler to pointer to function with int parameter, using the first one of the type conversion operators defined in Surrogate. That function is then invoked.
The call callable(10); actually is *(callable.operator void(*)(int))(10);.
The compiler has figured out that callable is used in a function call expression. Now, for a function call expression the compiler would like a function, function pointer, or object with operator() - as you already know.
In this case, callable is none of these. But callable can be converted to one of these, namely to a function pointer. Given the call expression, in particular the int argument, overload resolution selects void(*)(int).
These are just user-defined conversion operators. User-defined conversion operators is a basic feature of C++ language, meaning that you can read about them in C++ book or in some tutorial.
Section 12.3.2 of language specification describes the syntax, but the rules that govern their usage by the compiler are scattered across the entire document and are relatively extensive. I.e. it is not something that can or should be explained in a SO post.
Find a book. Come back here if something in the book is not clear to you.
Since my shifting from C to C++ I have a question on STL's formatting output. How ostreams tell one basic type from another?
In C with its printf and formatting strings it was pretty straightforward, but in C++ ostreams somehow distinguish basic types automatically. It puzzles me.
For example, in the following code,
int i;
float f;
std::cout << i << std::endl;
std::cout << f << std::endl;
how cout "knows" that i is an int and f is a float?
The compiler converts the operators to function calls. So that
std::cout << i
becomes
operator<<(std::cout, i)
Somewhere buried deep in the bowels of the standard library headers there are function declarations (functionally equivalent to):
std::ostream& operator<<(std::ostream& o, int i);
std::ostream& operator<<(std::ostream& o, double d);
That is, operator<< is overloaded. When the function call is made, the compiler chooses the function overload which is the best match to the arguments passed in.
In the case of std::cout << i, the int overload is chosen. In the case of std::cout<<d, the double overload is chosen.
You can see function overloading in action fairly simply with a contrived example:
#include <stdio.h>
void print(int i) {printf("%d\n", i);}
void print(double d) {printf("%f\n", d);}
int main()
{
int j=5;
double f=7.7;
print(j);
print(f);
}
Producing the output:
5
7.700000
Try it for yourself: http://ideone.com/grlZl.
Edit: As Jesse Good points out, the functions in question are member functions. So really we have:
std::cout << i
becomes
std::cout.operator<<(i)
And in the headers there are declarations (equivalent to):
class ostream {
ostream& operator<<(int i);
ostream& operator<<(double d);
...
};
The same basic idea holds, however.
There are operator<< overloads for each type (int, float etc).
The compiler will then choose the correct one at compile time.
In general, the operator<< have the form std::ostream& operator<<(std::ostream& stream, int number ), where the function is a global function defined in the std namespace. You can overwrite the definition of this function by declaring it in your own namespace (this is done via Argument Dependent Lookup).
The fact the function returns a reference to the stream, means you can string them together. Just remember, whenever you see operator<<, it really is just a function call.
If you want to have a look, and you're using VS, open
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\ostream.
There you'll find all the definitions if you're curious.
Overload resolution on the second argument to operator<<
Function overloading is a form of compile-time polymorphism. A simple example:
void times_two(int& x) { x *= 2; }
void times_two(double& x) { x *= 2; }
int i = 2;
double d = 2.5;
times_two(i); // i now 4
times_two(d); // d now 5.0
In the case of std::ostreams such as std::cout, the operator<<() functions overload in a similar way. From the Standard Library shipped with GCC 3.4.4:
__ostream_type&
operator<<(int __n);
__ostream_type&
operator<<(double __f);
It's an overloaded ostream operator <<. In c++ you can overload a function name based on it's parameters. This is basically what's happening here. http://www.cplusplus.com/reference/iostream/ostream/operator%3C%3C/
C++ does not allow polymorphism for methods based on their return type. However, when overloading an implicit conversion member function this seems possible.
Does anyone know why? I thought operators are handled like methods internally.
Edit: Here's an example:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
}
Conversion operators are not really considered different overloads and they are not called based on their return type. The compiler will only use them when it has to (when the type is incompatible and should be converted) or when explicitly asked to use one of them with a cast operator.
Semantically, what your code is doing is to declare several different type conversion operators and not overloads of a single operator.
That's not return type. That's type conversion.
Consider: func() creates an object of type func. There is no ambiguity as to what method (constructor) will be invoked.
The only question which remains is if it is possible to cast it to the desired types. You provided the compiler with appropriate conversion, so it is happy.
There isn't really a technical reason to prevent overloading of functions on the result types. This is done in some languages like Ada for instance, but in the context of C++ which has also implicit conversions (and two kind of them), the utility is reduced, and the interactions of both features would quickly leads to ambiguities.
Note that you can use the fact that implicit conversions are user definable to simulate overloading on result type:
class CallFProxy;
CallFProxy f(int);
class CallFProxy {
int myParameter;
CallFProxy(int i) : myParameter(i) {}
public:
operator double() { std::cout << "Calling f(int)->double\n"; return myParameter; }
operator string() { std::cout << "Calling f(int)->string\n"; return "dummy"; }
};
Overload resolution chooses between multiple candidate functions. In this process, the return type of candidates is indeed not considered. However, in the case of conversion operators the "return type" is critically important in determining whether that operator is a candidate at all.