There's an asymmetry between the left and right operands of a binary operator defined within a class that doesn't exist when the binary operator is defined outside the class. Because the type of the left operand is used by the compiler to determine the class in which to find the operator's definition, the compiler won't apply any conversions to the operand. The right operand, however, may be freely converted as needed.
$ cat t.cc struct bn { bn() { } bn operator + (const char *) const { return *this; } bn(const char *) { } }; int main() { bn b; b = b + "1000000000000"; b = "1000000000000" + b; } $ g++ -c -ansi -pedantic -Wall t.cc t.cc: In function int main(): t.cc:12: no match for const char[14] + bn& operator $ CC -c t.cc "t.cc", line 12: Error: The operation "const char* + bn" is illegal. 1 Error(s) detected. $
Even though there is a conversion from character-array literals to big numbers, the compiler won't apply it in the second case when looking for the definition of + within any defined classes.
When the operator is define outside the class, the compiler uses overload resolution to determine the proper operator implementation, and both operands may be freely converted as needed.
$ cat t.cc struct bn { bn() { } bn(const char *) { } }; bn operator + (const bn & a, const bn &) { return a; } int main() { bn b; b = b + "1000000000000"; b = "1000000000000" + b; } $ g++ -c -ansi -pedantic -Wall t.cc $ CC -c t.cc $
Most of the answers to this question were wrong. Many of them mentioned something about temporaries, which is a good reason to avoid conversions all together, but doesn't really have anything to do with defining operators within or externally to a class.
struct Device { bool init(int maj, int min); }; struct FileSystem : Device { virtual bool init(int maj, int min); }; struct Ext3 : FileSystem { bool init(int maj, int min); };
indicate which version of init()
gets called in each of the following:
a) Device * dp = new Ext3(); dp->init(3, 5); b) Ext3 fs3; FileSystem & fs = fs3; fs.init(3, 6);
Be sure to explain your answers.
This is straight off the lecture notes. For a, the first question is "is
init()
virtual?" dp
's static type is Device
; because Device
is the top of the inheritance hierarchy and init()
is non-virtual in
Device
, the answer is "No."
The second question is "Where is init()
?". Because Device::init()
is
non-virtual, we use static lookup to answer the question. Again dp
's
static type is Device
and the search for init()
starts and ends there.
For b, fs
's static type is FileSystem
, and FileSystem::init()
is
virtual. fs
's dynamic type is Ext3
, and dynamic lookup finds
Ext3::init()
.
The correct answers, of which where were two, were exactly correct, while the wrong answers, of which there were two, were exactly backwards.
#define debugp(msg) if (debug_print) std::cerr << msg << ".\n"
The answer to that question involved using a template value parameter to represent the boolean controlling the print statement.
This test asks you to solve the same problem - implement a conditional debugging print statement using template functions - except this time your solution should use template specialization.
By default, we want no debugging print statements, so the default debugging behavior should be to do nothing:
template < bool print > inline void debugp(const std::string & msg) { }
When we want debugging print statements, print
will be true, and that's
what we specialize on:
template < > inline void debugp<true>(const std::string & msg) { std::cerr << msg << "\n"; }
Just to make sure:
$ cat t.cc #include <iostream> #include <string> template < bool print > inline void debugp(const std::string & msg) { } template < > inline void debugp<true>(const std::string & msg) { std::cerr << msg << "\n"; } int main() { debugp<DEBUGP>("Hey, it works!"); } $ g++ -DDEBUGP=false -o t t.cc $ ./t $ CC -DDEBUGP=false -o t t.cc $ ./t $ g++ -DDEBUGP=true -o t t.cc $ ./t Hey, it works! $ CC -DDEBUGP=true -o t t.cc $ ./t Hey, it works! $
No answers to this question were right, or even close to being right.
move r0 a
is not minimal and can be optimized into an empty schedule. Do you think your colleague is correct or not? Explain.
Oh lucky students. It turns out your colleague was right because I messed up the question. The complete schedule should have been
move a r0
which is a bit harder to answer.
All answers to this question were correct (possibly because I answered this question in an e-mail message), but some answers were more correct than others due to the quality of their explanation, which should have mentioned the effects of each schedule on storage.
Before we leave this question, I want to share with you an answer I consider absolute gem of an example of the type of answers I occasionally get:
I don't think this is not minimal.
You might want to try your hand at figuring out if this is a correct or incorrect answer.
This page last modified on 27 April 2004.