То, что вы в конечном итоге хотите, я думаю, это иметь тип пользователя
Vector<T, N>
И в зависимости от N
пользователь получит несколько разных вещей. Первый не выполнит этого, а второй - по цене дублирования кода.
Что вы можете сделать, это инвертировать наследство:
template<typename T, size_t N> struct VectorBase
{
};
template<typename T> struct VectorBase<T, 2>
{
};
template<typename T> struct VectorBase<T, 3>
{
};
template<typename T, size_t N> struct Vector : VectorBase<T, N>
{
};
И реализовать несколько функций, которые зависят только от N, являющегося некоторым конкретным значением в соответствующем базовом классе. Вы можете добавить в них защищенный деструктор, чтобы пользователи не могли удалять экземпляры Vector
через указатели на VectorBase
(обычно они даже не должны иметь возможность именовать VectorBase
: поместить эти базы в некоторое пространство имен реализации, например detail
).
Другая идея - объединить это решение с тем, которое упоминалось в другом ответе. Унаследовать конфиденциально (а не публично, как указано выше) и добавить функции-оболочки в производный класс, которые вызывают реализации базового класса.
Еще одна идея состоит в том, чтобы использовать только один класс, а затем enable_if
(используя boost::enable_if
), чтобы включить или отключить их для определенных значений N
, или использовать такой преобразователь типа int, который намного * 1021 проще *
struct anyi { };
template<size_t N> struct i2t : anyi { };
template<typename T, size_t N> struct Vector
{
// forward to the "real" function
void some_special_function() { some_special_function(i2t<N>()); }
private:
// case for N == 2
void some_special_function(i2t<2>) {
...
}
// case for N == 3
void some_special_function(i2t<3>) {
...
}
// general case
void some_special_function(anyi) {
...
}
};
Таким образом, он полностью прозрачен для пользователя Vector
. Это также не добавит дополнительных затрат пространства для компиляторов, выполняющих пустую оптимизацию базового класса (довольно часто).