Obfuscated C++
- By Rob Murray
- September 26, 2000
Last Month's Obfuscated C++
Last month we asked you to explain the semantics of the macro B in the following code. This example uses template partial specializations. I compiled it successfully using GCC 2.8.1, but many other compilers don't yet implement this feature correctly:
template <unsigned long I, unsigned i>
struct o
{
enum{OO=I%10+i*o<I/10,i>::OO};
};
template <unsigned i>
struct o<0,i>
{
enum {OO=0};
};
#define B(i,I) (o<i,I>::OO)
First, we examine the macro B. It uses the same argument names as the template, but has them reversed. The names of the formal macro arguments are not significant, so let's reverse them so that they match the template:
#define B(I,i) (o<I,i>::OO)
The (rewritten) macro B(I,i) performs a compile-time conversion of an integer constant I from base i to base 10. I must be less than 10. For instance, the value of
B(100,8)
is 64, because that is the base-10 value of 100 base 8.
This file defines two templates. The first templateo<I,i>is a normal template definition. This template sets the value of o::OO to I base i. It does this by extracting the low-order digit (I%10) and then adding i times the value obtained by recursively instantiating o<I/10,i>.
The second template is a partial specialization of the general template. (Note the syntactical differencethe partial specialization has an argument list after the template name, the general template does not.) This specialization is used to instantiate the template if and only if the first template argument is 0. This terminates the compile-time recursion.
For instance, to calculate B(100,8):
- we instantiate O<100,8> using the general template definition;
- which in turn instantiates O<10,8> using the general template definition;
- which in turn instantiates O<1,8> using the general template definition;
- which in turn instantiates O<0,8> using the partial specialization.
This completes the recursion, and the resulting values of the OO members are used to calculate the final result.
|
This Month's Obfuscated C++
Explain the output of the following program:#include <iostream>
#include <functional>
using namespace std;
template<class op>
void g(int size, op o, const char* sep = "") {
for(int i = 0; i < size; ++i)
cout << o(i) << sep;
}
template<class op,int size>
struct w {
char* operator()(int a) {
return g(size,binder1st<op>(op(),a),"\t"),"\n";
}
};
template<class op,int size>
void
x(){
g(size, w<op,size>());
}
int main(){
x<multiplies<int>,6>();
return 0;
}
Rob Murray is Director, Engineering at the Irvine office of Net Explorer, an object-oriented software consulting company based in Houston, TX. He has taught C++ at technical conferences since 1987 and is the author of C++ Strategies and Tactics. He was the founding editor of C++ Report and can be contacted at [email protected].