I have this code:
class LazyStream {
ostream& output;
std::list<string> pending;
public:
//...
LazyStream operator++(int n = 0){
LazyStream other(output);
if (n>0) output << "<#" << n << ">";
output << pending.pop_front();
return other;
}
I do not understand the meaning of getting an int value for the operator++. I though it was just an indication that the operator is a suffix. How can the operator get a number?
Can someone give an example?
Thanks
Well, it's the first time I've seen the int defaulted.
As you point out, a "dummy" int parameter is use to
distinguish the post-fix operator from the prefix. Except that
it's not really a dummy: when you write:
myVar ++;
and myVar has a user defined postfix ++, the compiler
actually calls it as:
myVar.operator++( 0 );
And there's nothing to stop you from writing:
myVar.operator++( 42 );
(Of course, having to do so, as in this case, sort of defeats
the purpose of operator overloading.)
Apparently it's possible to pass that argument if you use function call syntax to call that operator. This code compiles cleanly with gcc and outputs 42:
#include <iostream>
struct Stream {
Stream operator++(int n)
{
std::cout << n;
return *this;
}
};
int main()
{
Stream s;
s.operator++(42);
}
If I give it default value, it gives a warning (with -pedantic flag) that it cannot have one, though. It sort of makes sense, because if you also defined prefix increment, then the call s.operator++() would be ambiguous. I didn't, however, find anything in the standard explicitly prohibiting the default value.
Related
for the expression
(func1() * func2()) + func3()
will func1() * func2() be evaluated first as it has brackets or can the functions be called in any order like
first func3() and then (func1() * func2())
The functions can be called in any order.
Precedence of operators has got nothing to do anything with the order of evaluation of operands.
The C or C++ Standard doesn't determine the order in which the functions would be called. .
The order of evaluation of subexpressions, including
the arguments of a function call and
operands of operators (e.g., +, -, =, * , /), with the exception of:
the binary logical operators (&& and ||),
the ternary conditional operator (?:), and
the comma operator (,)
is Unspecified
For example
int Hello()
{
return printf("Hello"); /* printf() returns the number of
characters successfully printed by it
*/
}
int World()
{
return printf("World !");
}
int main()
{
int a = Hello() + World(); //might print Hello World! or World! Hello
/** ^
|
Functions can be called in either order
**/
return 0;
}
You can't make any assumptions about the order in which these functions will be called. It's perfectly valid for the compiler to call these functions in any order, assign the results to temporaries, and then use these temporary values to calculate the result of the expression.
These calls can be made in any order. You want to learn about C++ sequence points C++ sequence points.
Parenthesis in C/C++ force order of operations. func1() * func2() will be added to func3(), but the compiler can choose to call the functions in whatever order it wishes before passing in the results to the multiplication / addition operation.
It's natural to think that A+B is evaluated before C in this psudocode:
(A+b)*C
But in fact this is not so. The Standard says that the order of evaluation for all expressions is "Unspecified", unless otherwise specified by the Standard:
5/4 [expr]:
Except where noted, the order of
evaluation of operands of individual
operators and subexpressions of
individual expressions, and the order
in which side effects take place, is
unspecified
The Standard then goes on to identify a parenthesized expression as a "Primary expression" but does not specify the order of evaluation for Primary expressions. (5.1/5).
In Standardese, "Unspecified" does not mean "Undefined." Rather it means "Implementation Defined, but no documentation is required." So you might not even be able to say what the order of evaluation is for a specific compiler.
Here is a simple program illustrating the behavior:
#include <iostream>
#include <string>
using namespace std;
class Foo
{
public:
Foo(const string& name) : name_(name) {++i_; cout << "'" << name << "'(" << i_ << ")\n"; };
operator unsigned() const { return i_; }
Foo operator+(const Foo& rhs) const { string new_name = name_; new_name += "+"; new_name += rhs.name_; return Foo(new_name); }
private:
string name_;
static unsigned i_;
};
unsigned Foo::i_ = 0;
int main()
{
(Foo("A") + Foo("B")) + Foo("C");
}
On my MSVC10 running in Debug/x64 on Win7, the output happened to be:
'C'(1)
'B'(2)
'A'(3)
'A+B'(4)
'A+B+C'(5)
I've seen this used by other people and it looks really clever, but I'm not sure if it's good or bad practice. It works, and I like the way it works, personally, but is doing this actually useful in the scope of a larger program?
What they've done is dynamically allocate some data type inside the actual function argument, and delete it in the function. Here's an example:
#include <iostream>
class Foo {
private:
int number;
public:
Foo(int n) : number(n) { }
int num() { return number; }
Foo* new_num (int i) { number = i; }
};
void some_func (int thing, Foo* foo);
int main() {
std::cout << "Enter number: ";
int n;
std::cin >> n;
some_func(n, new Foo(0)); // <-- uses the 'new' operator with a function argument
return 0;
}
// calculates difference between 'thing' and 'n'
// then puts it inside the Foo object
void some_func (int thing, Foo* foo) {
std::cout << "Enter another number: ";
int n;
std::cin >> n;
std::cout << "Difference equals " << foo->new_num(thing - n)->num() << std::endl;
delete foo; // <-- the Foo object is deleted here
}
I knew that it was possible to use operators in function arguments, but I was only aware of doing this with the operators on levels 2, 4 through 15, and 17, as well as the assignment operators, ? :, ++ and --, unary + and -, !, ~, * and &, sizeof and casts. Stuff like this:
foo((x < 3)? 5 : 6, --y * 7);
bar(player->weapon().decr_durability().charge(0.1), &shield_layers);
So, I actually have two questions.
Is the new-as-an-argument good practice?
Since apparently any operator returning a type works if new works, are using these good practice?
::, new [], throw, sizeof..., typeid, noexcept, alignof
No, this is not clever at all. It takes a function that could be simpler and more general and reduces its capabilities for no reason, while at the same time creating an entry point into your program for difficult-to-debug bugs.
It's not clear to me exactly what Foo::new_num is meant to do (right now it doesn't compile), so I won't address your example directly, but consider the following two code samples:
void bad_function(int i, F * f)
{
f->doSomething(i);
delete f;
}
// ...
bad_function(0, new F(1, 2, 3));
versus
void good_function(int i, F & f)
{
f.doSomething(i);
}
// ...
good_function(0, F(1, 2, 3));
In both cases you allocate a new F object as part of the method call and it's destroyed once you're done using it, so you get no advantage by using bad_function instead of good function. However there's a bunch of stuff you can do with good_function that's not so easy to do with bad_function, e.g.
void multi_function(const std::vector<int> & v, F & f)
{
for(int i : v) { good_function(i, f); }
}
Using the good_function version means you're also prevented by the language itself from doing various things you don't want to do, e.g.
F * f; // never initialized
bad_function(0, f); // undefined behavior, resulting in a segfault if you're lucky
It's also just better software engineering, because it makes it a lot easier for people to guess what your function does from its signature. If I call a function whose purpose involves reading in a number from the console and doing arithmetic, I absolutely do not expect it to delete the arguments I pass in, and after I spent half an hour figuring out what's causing some obscure crash in some unrelated part of the code I'm going to be furious with whoever wrote that function.
By the way, assuming that F::doSomething doesn't alter the value of the current instance of F in any way, it should be declared const:
class F
{
void doSomething(int i) const;
// ...
};
and good_function should also take a const argument:
void good_function(int i, const F & f);
This lets anyone looking at the signature confidently deduce that the function won't do anything stupid like mess up the value of f that's passed into the function, because the compiler will prevent it. And that in turn lets them write code more quickly, because it means there's one less thing to worry about.
In fact if I see a function with a signature like bad_function's and there's not an obvious reason for it, then I'd immediately be worried that it's going to do something I don't want and I'd probably read the function before using it.
I was going through the book Effective C++ by Scott Meyers and while reading Item 3 - Use const whenever possible found this example quite misleading.
My question is - How can an array access return a reference at the interested index rather than the item at that index.
Also attaching the program for reference here that I executed to confirm that this is happening
#include <iostream>
#include <string>
using namespace std;
class TextBlock
{
public:
explicit TextBlock(const std::string str) : text(str) {}
const char& operator[](std::size_t position) const { return text[position]; }
char& operator[](std::size_t position) { return text[position]; }
std::string get_text() { return text; }
private:
std::string text;
};
int main()
{
TextBlock tb("Hello");
cout << "Before calling operator overloading " << tb.get_text() << "\n";
tb[0] = 'I';
cout << "After calling operator overloading " << tb.get_text() << "\n";
return 0;
}
I got the corresponding output
Before calling operator overloading Hello
After calling operator overloading Iello
Is the observed behaviour something specific to operator overloading?
My question is - How can an array access return a reference at the interested index rather than the item at that index.
It isn't an array access. You are calling the following overload of std::string when you do text[position].
char& std::string::operator [] ( std::size_t index ) ;
which returns a reference to a character in the specified location of the string, which effectively is a container of chars. This is similar to how other containers work, such as std::map or std::vector. This behaviour is made possible by overloading the indexing operator for a class. It would otherwise be undefined since indexing is only possible on pointers/arrays or classes with the overload implemented.
With that said, it should be kept in mind that array indexing is effectively a pointer dereference, which means it can be bound to a reference in the same way and lead to the same results, like below (try it out). That is because carray[i] is equivalent to *(carray + i) which is one way to tell the compiler it is okay to implicitly cast your pointer to a reference.
char& operator [] ( std::size_t i ) { return carray[i]; }
...
char carray[10];
There are good reasons for the indexing operator to be implemented as such. It effectively allows you to treat std::string like you would a char[]; you can assign any given index a value as well as access any given index to get a value.
#include <iosteam>
using namespace std;
Class A
{
int k;
public:
int getK() { return k; }
operator int() { return k; }
};
int main()
{
A a;
cout << a.getK() << " " << int(a) << endl;
}
What's the difference, and which one should I use? I'm wondering if typecasting returns a reference and getK returns a copy.
The only difference is that typecasting can be implicit.
int i = a;
Note that c++11 allow you to force cast operator to be explicitly called.
explicit operator int() { return k; }
They are both returning copies. Providing a cast operator usually is for when casting is necessary. For example you might do something like this maybe:
#include <iosteam>
using namespace std;
Class A
{
double k;
public:
A(double v) : k(v) {}
double getK() { return k; }
operator int() { return static_cast<int>(k); }
};
int main()
{
A a(3.14);
cout << a.getK() << " " << int(a) << endl; // 3.14 3
}
In general I avoid cast operators entirely because I prefer explicit casting.
It returns what the return type is. If you cast to a reference, then that's what you get back. What you're doing both times is making a copy.
The "difference" is what your method does. Your "cast" could add 5 to it and then return it. Or anything you want.
As for appropriateness, as chris said in the first comment, it's usually a "is your class a or not?" type question. Operators should be done for common conversions because your class operates as something, not merely to extract something from it. That's why it's a separate function to convert strings to integers, rather than being merely a cast on the string class. Whereas a complex number type can often be cast directly to a double or int, though that strips information from it. That the conversions can be "abused" is actually why some modern languages don't allow operator overloading. Others take the approach of while it can be abused, it can also be awesome. That's the C++ philosophy on most things: give all the tools, let the user do good or bad with them.
I hope that made sense.
for the expression
(func1() * func2()) + func3()
will func1() * func2() be evaluated first as it has brackets or can the functions be called in any order like
first func3() and then (func1() * func2())
The functions can be called in any order.
Precedence of operators has got nothing to do anything with the order of evaluation of operands.
The C or C++ Standard doesn't determine the order in which the functions would be called. .
The order of evaluation of subexpressions, including
the arguments of a function call and
operands of operators (e.g., +, -, =, * , /), with the exception of:
the binary logical operators (&& and ||),
the ternary conditional operator (?:), and
the comma operator (,)
is Unspecified
For example
int Hello()
{
return printf("Hello"); /* printf() returns the number of
characters successfully printed by it
*/
}
int World()
{
return printf("World !");
}
int main()
{
int a = Hello() + World(); //might print Hello World! or World! Hello
/** ^
|
Functions can be called in either order
**/
return 0;
}
You can't make any assumptions about the order in which these functions will be called. It's perfectly valid for the compiler to call these functions in any order, assign the results to temporaries, and then use these temporary values to calculate the result of the expression.
These calls can be made in any order. You want to learn about C++ sequence points C++ sequence points.
Parenthesis in C/C++ force order of operations. func1() * func2() will be added to func3(), but the compiler can choose to call the functions in whatever order it wishes before passing in the results to the multiplication / addition operation.
It's natural to think that A+B is evaluated before C in this psudocode:
(A+b)*C
But in fact this is not so. The Standard says that the order of evaluation for all expressions is "Unspecified", unless otherwise specified by the Standard:
5/4 [expr]:
Except where noted, the order of
evaluation of operands of individual
operators and subexpressions of
individual expressions, and the order
in which side effects take place, is
unspecified
The Standard then goes on to identify a parenthesized expression as a "Primary expression" but does not specify the order of evaluation for Primary expressions. (5.1/5).
In Standardese, "Unspecified" does not mean "Undefined." Rather it means "Implementation Defined, but no documentation is required." So you might not even be able to say what the order of evaluation is for a specific compiler.
Here is a simple program illustrating the behavior:
#include <iostream>
#include <string>
using namespace std;
class Foo
{
public:
Foo(const string& name) : name_(name) {++i_; cout << "'" << name << "'(" << i_ << ")\n"; };
operator unsigned() const { return i_; }
Foo operator+(const Foo& rhs) const { string new_name = name_; new_name += "+"; new_name += rhs.name_; return Foo(new_name); }
private:
string name_;
static unsigned i_;
};
unsigned Foo::i_ = 0;
int main()
{
(Foo("A") + Foo("B")) + Foo("C");
}
On my MSVC10 running in Debug/x64 on Win7, the output happened to be:
'C'(1)
'B'(2)
'A'(3)
'A+B'(4)
'A+B+C'(5)