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 (12)

  1. Kristofer says:

    Funny stuff.. πŸ˜€

  2. Anders Dalvander says:

    "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.

  3. 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 πŸ™‚

  4. Anders Dalvander says:

    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];

    }

  5. Anders Dalvander says:

    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>();
    }

  6. Anders Dalvander says:

    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”));
    }

  7. Anders Dalvander says:

    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());
    }

  8. Anders Dalvander says:

    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;
    }

  9. 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 πŸ™‚

  10. Lauren Smith says:

    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.

  11. Hehe, I need to figure out from Anders Dalvander  who came out with the templates-specialization solution. God have mercy on people who get to maintain his code πŸ™‚

  12. Lauren Smith says:

    The last example code, that is.

Skip to main content