Why, and how to omit the general template case
This technique can be useful for eg: when you need a wrapper to strictly prohibit accidentally copying something by value. In that case, we can omit defining the general case. The idea is to leave the general case out, and define only the permitted specializations. This will provide the effect of generating an error if the programmer uses a type outside of the specializations described in the code. Diagnostics can be improved in C++20 with the use of Concepts (not shown here).
We do this by forward declaring the general case, and omitting the actual definition of it.
\In this example, the compiler generates code only for pointers and reference types
/*
Template specialization, excluding the general case
- the template does not exist in the general case; only the specialisations
- trying to instantatate a not specialized case will throw an error
*/
// fwd. declaration, omits the generic template
template <typename T>
class PRefOnlyValue;
// specialization to support pointer types
template <typename T>
class PRefOnlyValue<T*> {
public:
explicit PRefOnlyValue(T* p) : v(*p) { }
private:
T v;
};
// specialization to support reference types
template <typename T>
class PRefOnlyValue<T&> {
public:
explicit PRefOnlyValue(T& p) : v(p) { }
private:
T v;
};
void main() {
int i = 5;
int* p = &i;
int& ref = i;
PRefOnlyValue<int*> v1(p);
PRefOnlyValue<int&> v2(ref);
// PRefOnlyValue<int> v3(i); // this will not work.
}