Почему специализации шаблонов функций не разрешены внутри класса?

После того, как я нашел ответы на многие мои вопросы о 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");
}
};
};
};

9

Решение

Базовая специализация:

В .ч:

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: вложенные шаблоны классов явно не специализированы.

Неважно, является ли это определение внутри класса или в пространстве имен. Дело в том, что это не является точной частичной специализацией — у этой функции нет определенного класса контекста (какие члены вы хотите вызвать). Другими словами — когда вы специализируете член, вы фактически пытаетесь специализировать весь содержащий класс, но не сам член. И компилятор не может этого сделать, потому что класс еще не определен полностью. Так что это ограничение дизайна шаблона. И если бы это действительно работало — шаблоны были бы полностью эквивалентны простым макросам.
(И вы, вероятно, можете решить вашу задачу с помощью некоторой макро магии.)

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]