I am wondering if lazy evaluation in C ++ can be implemented in a reasonable way. If so, how would you do it?
Yes, this is possible and often done, for example. for matrix calculations. The main mechanism for this is operator overload. Consider the case of matrix addition. A function signature usually looks something like this:
matrix operator +(matrix const& a, matrix const& b);
Now, to make this function lazy, it is enough to return the proxy instead of the actual result:
struct matrix_add; matrix_add operator +(matrix const& a, matrix const& b) { return matrix_add(a, b); }
Now all you need to do is write this proxy:
struct matrix_add { matrix_add(matrix const& a, matrix const& b) : a(a), b(b) { } operator matrix() const { matrix result;
The magic lies in the operator matrix() method, which is an implicit conversion operator from matrix_add to a simple matrix . Thus, you can combine several operations (of course, providing the appropriate overload). Evaluation is only performed when the end result is assigned to the matrix instance.
EDIT I should have been more explicit. Be that as it may, the code does not make sense, because although the evaluation is lazy, it still happens in one expression. In particular, another add-on will evaluate this code if the matrix_add structure matrix_add not changed to ensure that it is added to the chain. C ++ 0x greatly facilitates this by allowing variational patterns (i.e. lists of variable-length patterns).
However, one very simple case where this code really has real direct benefit is as follows:
int value = (A + B)(2, 3);
It is assumed here that A and B are two-dimensional matrices and that dereferencing occurs in Fortran notation, i.e. the above calculates one element from the sum of the matrix. Of course, it is wasteful to add all matrices. matrix_add to the rescue:
struct matrix_add {
Other examples abound. I just remembered that I recently implemented something that was connected. Basically, I had to implement a string class that should stick to a fixed, predefined interface. However, my particular class of strings concerned huge strings that were not actually stored in memory. Typically, the user simply accesses the small substrings from the source string using the infix function. I overloaded this function for my string type in order to return a proxy server containing a link to my string, as well as the desired start and end position. Only when this substring was actually used did it request the C API to retrieve this part of the string.