После того, как я нашел ответы на многие мои вопросы о stackoverflow, я столкнулся с вопросом, на который я не могу найти ответ, и я надеюсь, что кто-то готов помочь мне!
Моя проблема в том, что я хочу сделать явную шаблонизацию функции внутри класса в C ++. Мой компилятор (g ++) и взгляд на стандарт C ++ (§14.7.3) говорят мне, что эта специализация должна быть сделана в пространстве имен, в котором объявлен класс. Я понимаю, что это означает, что я не могу поместить специализацию в класс, но я не вижу смысла этого ограничения! Кто-нибудь знает, есть ли веская причина не допускать специализаций внутри класса?
Я знаю, что есть обходные пути, например, поместить функцию внутри структуры, но я хочу понять, почему язык имеет такой дизайн. Если есть веская причина, по которой нельзя запрещать использование специальных функций внутри класса, я думаю, я должен знать об этом, прежде чем пытаться обойти это.
Заранее спасибо!
Чтобы сделать мой вопрос немного более точным: Вот код из тестового примера, который иллюстрирует, что я хочу сделать:
#include <cstdio>
namespace MalinTester {
template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
SpecializationTest() {
privateVariable = 5;
};
virtual ~SpecializationTest() {};
void execute() {
execute<DIMENSIONALITY>();
};
private:
int privateVariable;
template <size_t currentDim>
static void execute() {
printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable);
execute<currentDim-1>();
}
template <>
static void execute<0>() {
printf("This is the base case. Current dim is 0.\n");
}
};
Это невозможно; G ++ говорит:
SpecializationTest_fcn.h:27: error: explicit specialization in non-namespace scope ‘class MalinTester::SpecializationTest<DIMENSIONALITY>’
SpecializationTest_fcn.h:28: error: template-id ‘execute<0>’ in declaration of primary template
Если я помещу функцию execute вне класса, в пространство имен MalinTester, это будет выглядеть так:
#include <cstdio>
namespace MalinTester {
template <size_t DIMENSIONALITY> class SpecializationTest {};
template <size_t currentDim>
void execute() {
printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable);
execute<currentDim-1>();
}
template <>
void execute<0>() {
printf("This is the base case. Current dim is 0.\n");
}
template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
SpecializationTest() {};
virtual ~SpecializationTest() {};
void execute() {
MalinTester::execute<DIMENSIONALITY>();
};
private:
int privateVariable = 5;
};
};
};
и я не могу использовать privatevariable в шаблонных версиях execute, так как это private в классе. я действительно хочу это личное, поскольку я хочу, чтобы мои данные были как можно более инкапсулированы.
Конечно, я могу отправить privateVariable в качестве аргумента функции, но я думаю, что было бы красивее избежать этого, и что мне действительно интересно, так это то, что у стандарта C ++ есть веская причина не разрешать явную специализацию, как в первом Пример кода выше.
@Arne Mertz: это обходной путь, который я пробовал, но он также не позволяет использовать privateVariable. И больше всего мне интересно, стоит ли так поступать. Поскольку мне не разрешено делать специализации функций-членов, возможно, мне не следует делать специализации функций, инкапсулированных в структуры внутри класса.
#include <cstdio>
namespace MalinTester {
template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
SpecializationTest() {
privateVariable = 5;
};
virtual ~SpecializationTest() {};
void execute() {
Loop<DIMENSIONALITY, 0>::execute();
};
private:
int privateVariable;
template <size_t currentDim, size_t DUMMY>
struct Loop {
static void execute() {
printf("This is the general case. Current dim is %d.\n", currentDim);
Loop<currentDim-1, 0>::execute();
}
};
template <size_t DUMMY>
struct Loop<0, DUMMY> {
static void execute() {
printf("This is the base case. Current dim is 0.\n");
}
};
};
};
Базовая специализация:
В .ч:
template <class T>
class UISelectorSlider : public UISelectorFromRange<T> {
public:
UISelectorSlider();
virtual ~UISelectorSlider();
private:
float width;
float getPositionFromValue(T value);
};
В .cpp под тем же пространством имен:
template <>
float UISelectorSlider<MVHue>::getPositionFromValue(MVHue value)
{
return width * (float)value / 360.0;
}
Если вы хотите специализированную функцию в пределах специализированного класса:
Внутри класса add (.h) (приватная функция):
private:
template <int I>
void foo();
Специализация внутри .cpp:
template <>
template <>
void UISelectorSlider<MVHue>::foo<3>()
{
// you can access private fields here
}
ОБНОВИТЬ:
Но вы не можете написать что-то вроде этого:
template <class T>
template <>
void UISelectorSlider<T>::foo<3>()
{
// you can access private fields here
}
Вы получите: error: вложенные шаблоны классов явно не специализированы.
Неважно, является ли это определение внутри класса или в пространстве имен. Дело в том, что это не является точной частичной специализацией — у этой функции нет определенного класса контекста (какие члены вы хотите вызвать). Другими словами — когда вы специализируете член, вы фактически пытаетесь специализировать весь содержащий класс, но не сам член. И компилятор не может этого сделать, потому что класс еще не определен полностью. Так что это ограничение дизайна шаблона. И если бы это действительно работало — шаблоны были бы полностью эквивалентны простым макросам.
(И вы, вероятно, можете решить вашу задачу с помощью некоторой макро магии.)
Других решений пока нет …