Thanks to Johannes for this interesting problem.
Let’s say you have a class template B where T is an arbitrary type and C is an integer template argument:
template <class T, int C> B;
B has two member functions with the same name:
template <class T, int C> void B::member(T _t); template <class T, int C> void B::member(T _t, int _i);
How do you make sure that the first member (the one with just a single argument) can only be called for instances of the class template with C==1? This is supposed to happen at compile time (runtime would be easy, of course).
One could (partially) specialize the whole class for C=1, which generates a whole lot of code bloat. Another solution would be to have a base class with only the two-argument member and a derived class (inheriting from B) implementing the single-argument member. This is also unsatisfactory because the derived class must have a name different from the first.
A more elegant solution is to have a private template class declaration encapsulated into the base class which gets instantiated when calling the single-argument member:
template class B {
template <int U> class BX {
public:
BX(B<T,U>* p) {}
};
public:
B();
// no problem here
void member(T _x, int _i);
// only valid if C==1
void member(T _x) {
BX<2-C> bx(this);
...
}
...
};
Only if C==1 will calling the single-argument member not fail, because BX<2-C> gets instantiated using a pointer to class B. If C!=1, the compiler spits out an error message saying that it can’t find a constructor with the appropriate argument. In this special case we could just have used BX<1>, but I wanted to show that any simple integer expression will do (see below).
Admittedly, the error message is a little clumsy, but it does the job. This example can easily be generalized – remember that the ternary operator will also be evaluated at compile time. All you have to do is provide a function of C that is equal to C for all permitted values of C, and different from C otherwise.
I’ve checked that this trick works using the Intel 10.1 and GNU 4.1.3 compilers.