3
\$\begingroup\$

I'm a newcomer to C++, from C#. I wrote a program that prints an ASCII checkerboard with a side length of the number passed to it (link to original Code Golf question).

stdafx.h

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

#include <iostream>
#include <sstream>
#include <string>

Checkers.cpp

#include "stdafx.h"

using std::cin;
using std::cout;
using std::endl;
using std::stoi;
using std::string;
using std::stringstream;

string header(int num);

template <bool white>
string body(const string &head, int num);

template <bool white>
stringstream& append_body(stringstream &stream, int rem, int approx);

int _tmain(int argc, _TCHAR* argv[])
{
    int num;

    if (argc == 1 || ((num = stoi(argv[1])) < 0))
    {
        cout << "Usage: ./Checkers [nonnegative int]" << endl;
        return 1;
    }

    switch (num)
    {
    case 0:
        return 0;
    case 1:
        cout << "+--+" << endl << "|  |" << endl << \
            "|  |" << endl << "+--+" << endl;
        return 0;
    }

    int rem = num % 2;
    int approx = num - rem;

    const string& head = header(num);
    string& wtail = body<true>(head, num);
    string& btail = body<false>(head, num);

    string& block = wtail + btail;

    stringstream stream;

    for (int i = 0; i < approx / 2; i++)
        cout << block;

    if (rem == 1)
        cout << wtail;

    cout << head << endl;

#ifdef _DEBUG
    cin.get();
#endif
}

string header(int num)
{
    string result;

    for (int i = 0; i < num; i++)
        result += "+--";

    return result + '+';
}

template <bool white>
string body(const string &head, int num)
{
    int rem = num % 2;
    int approx = num - rem;

    stringstream stream;
    stream << head << endl;

    append_body<white>(stream, rem, approx) << endl;
    append_body<white>(stream, rem, approx) << endl;

    return stream.str();
}

template <bool white>
stringstream& append_body(stringstream &stream, int rem, int approx)
{
    const char *const block =
        white ? "|  |##" : "|##|  ";

    for (int i = 0; i < approx / 2; i++)
        stream << block;

    stream << '|';

    if (rem == 1)
        stream << (white ? "  |" : "##|");

    return stream; // not a local so this is OK
}

Questions:

  • I intentionally had a little fun optimizing prematurely here, i.e. generating the header ("+--+") and body ("|##| |") strings only once instead of every loop. What could I do to increase readability without getting rid of each-loop optimizations like this?

  • When is it okay to use non-type template parameters, like I did in body? This means that you always have to rewrite your code when you want to offer a non-template alternative, correct?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$
  • To appreciate a power of non-type templates, try to implement body and append_body in plain C. You will see immediately why your approach is an abuse of templates.

  • Most important

    body() returns a temporary object:

        stringstream stream;
        ...
        return stream.str();
    

    and clang expectedly complains:

    error: non-const lvalue reference to type
      'basic_string<[3 * ...]>' cannot bind to a temporary of type
      'basic_string<[3 * ...]>'
    string& wtail = body<true>(head, num);
            ^       ~~~~~~~~~~~~~~~~~~~~~
    
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.