C++: Weird looping mechanism
In the old days (sigh!!!) when I used to code in C++, I unfortunately had a friend with a knack of doing/finding weird ways of programing. One day he asked me the following question
How do you write a program in C++ which does not have any looping construct and yet it can print a string n-times, even though the string is present only once in the source file and its not called multiple (n) times.
The answer goes as
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
cout << "Hello World" << endl;
}
};
int main(int argc, char* argv[])
{
MyClass mc[10];
return 0;
}
In C++, classes are not reference types and when you declare an array as above you actually create an initialized array of objects on the stack. So all the n-elements of the arrays is allocated and initialized by calling its default constructor. So for a n-element array the ctor is called n-times and you can print the string as many times using this.
Why would someone ever need to do something like this, beats me :). This became a sort of joke between us and when I joined MSFT and started working on .NET and sent him an email, saying that I was happy working in a language where you cannot do this kind of a thing.
When I first saw the bullet in the feature list of C# 3.0 that read "collection initializer" I was a bit scared. I thought maybe C# would support some construct in which the compiler will initialize all the elements of a collection/array by allocating the element with calls to default/some ctor. Fortunately thats not the case. For an example on object/collection initializer in C# 3.0 see here.
Comments
- Anonymous
April 17, 2006
Funny stuff.. :D - Anonymous
April 17, 2006
"How do you write a program in C++ which does not have any looping construct or conditional constructs and yet it outputs the numbers 0 through 100, and the numbers 100 through 0."
You can't imagine all the different ways people at work solved that one. - Anonymous
April 17, 2006
Anders, do share couple of them, here or at your blog. It'll be a nice read. Maybe I'd add how I solved it the first time when I heard the problem :) Or that I suggested memory optimization (??) by putting the writeline in finalizer as well so that you can do with half the number of objects. At that time I was not aware of the cost/complexity of finalization in .NET :) - Anonymous
April 18, 2006
First solution:
#include <iostream>
struct foo
{
foo()
{
std::cout << ++i << std::endl;
}
~foo()
{
std::cout << i-- << std::endl;
}
static int i;
};
int foo::i = 0;
int main()
{
foo f[100];
// The following also works.
// delete [] new foo[100];
} - Anonymous
April 18, 2006
Second solution, using template specialization:
#include <iostream>
template <int i>
void PrintNumbers()
{
std::cout << i << std::endl;
PrintNumbers<i + 1>();
std::cout << i << std::endl;
}
template <>
void PrintNumbers<101>()
{
}
int main()
{
PrintNumbers<1>();
} - Anonymous
April 18, 2006
Third solution, using STL.
#include <iostream>
#include <vector>
#include <numeric>
#include <iterator>
int main()
{
std::vector<int> w(100, 1);
std::partial_sum(w.begin(), w.end(), w.begin());
std::copy(w.begin(), w.end(), std::ostream_iterator<int>(std::cout, "n"));
std::copy(w.rbegin(), w.rend(), std::ostream_iterator<int>(std::cout, "n"));
} - Anonymous
April 18, 2006
Fourth solution, another STL solution.
#include <iostream>
#include <algorithm>
#include <iterator>
struct AddValue
{
AddValue() : miValue(1) {}
int operator()() { return miValue++; }
int miValue;
};
struct SubValue
{
SubValue() : miValue(100) {}
int operator()() { return miValue--; }
int miValue;
};
int main()
{
std::generate_n(std::ostream_iterator<int>(std::cout, "n"), 100, AddValue());
std::generate_n(std::ostream_iterator<int>(std::cout, "n"), 100, SubValue());
} - Anonymous
April 18, 2006
Fifth solution, made by the IT-guy. ;)
#include <iostream>
void Foo()
{
std::cout << "1" << std::endl;
std::cout << "2" << std::endl;
std::cout << "3" << std::endl;
// ...snip...
std::cout << "98" << std::endl;
std::cout << "99" << std::endl;
std::cout << "100" << std::endl;
std::cout << "100" << std::endl;
std::cout << "99" << std::endl;
std::cout << "98" << std::endl;
// ...snip...
std::cout << "3" << std::endl;
std::cout << "2" << std::endl;
std::cout << "1" << std::endl;
} - Anonymous
April 18, 2006
The template specialization is super cool. This is why C++ is so cool and most people who don't want to shoot themselves in the foot should avoid using it :) - Anonymous
April 19, 2006
I was going to comment on the template specialization, but I can't find my brain. I think it squeezed out my ears and escaped in fear when I looked at that code.
The leftover lizard brain recognizes that it could probably use a Perl script to generate that code. - Anonymous
April 19, 2006
The comment has been removed - Anonymous
April 19, 2006
The last example code, that is.