Частичная специализация шаблона - PullRequest
3 голосов
/ 06 марта 2011

Кто-нибудь знает, по каким правилам приведенный ниже код не компилируется?

template <class T>
struct B
{
    typedef T type;
};

template<class T>
struct X
{
};
template<class T>
struct X<B<T>::type*>//HERE I'M PARTIALLY SPECIALIZING (WELL, TRYING TO...)
{
};

Пожалуйста, смотрите комментарий внутри кода.

Ответы [ 3 ]

9 голосов
/ 06 марта 2011

Как вы думаете, это будет работать?Компилятор посмотрит, есть ли где-нибудь класс T, который имеет typedef "type" для вашего класса?

Просто не будет.Несмотря на то, что это указатель.

Помните, что, вероятно, ваш шаблон B, по-видимому, специализирован на местах, так что тип не всегда T *, но он не может быть выведен с помощью обратного инжиниринга.те, кто не понимает мой ответ полностью, просят компилятор найти класс U такой, что B :: type - это класс, который вы передаете в качестве параметра.

class Foo;
class Bar;

template<> struct B<Foo>
{
  typedef int type;
};

template<> struct B<Bar>
{
  typedef int type;
};

X<int*> // ambiguous, T is Foo or Bar?

Трудно точно понять, почему вы пытаетесь делать то, что вы есть.Вы можете выполнить частичную специализацию для всех указателей, а затем полную специализацию для конкретных указателей, которая может быть реализована в рамках другого шаблона.

4 голосов
/ 06 марта 2011

Вам необходимо использовать ключевое слово typename как,

template<class T>
struct X<typename B<T>::type*>
{
};

Это потому что B<T>::type является зависимым именем. Так что typename требуется!

-

EDIT:

Даже после помещения typename он не компилируется. Я думаю, это потому, что вычитание типа T в B<T> из X<U> сложно или, возможно, невозможно для компилятора. Поэтому я считаю, что это не выводимый контекст.

Смотрите похожий пример здесь и обсуждение:

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


Однако, если вы измените специализацию на это:

template<class T>
struct X<B<T> >
{
};

Тогда это становится выводимым контекстом, и поэтому будет компилироваться.

0 голосов
/ 06 марта 2011

Если вы уже добавили typename в соответствии с предложением Nawaz.

Проблема точно объясняется в сообщении об ошибке, с которым вы сталкиваетесь: «параметр шаблона не выводится при частичной специализации B<T>::type*. Проблема в том, чтоB<T>::type и T абсолютно одинаковы для всех типов T. Рассмотрим следующий пример:

class MyClass1 {};
typedef typename B<MyClass>::type MyClass2; //(*)

X<MyClass*> obj1;
X<MyClass2*> obj2;

Результатом строки (*) является тип MyClass2, который по существу равен MyClass1.Итак, obj1 и obj2 должны быть объектами одного класса. Теперь, какую версию шаблона X они должны использовать?

Если вы ожидаете специализированную версию X, скажите мнеесли ответ должен быть таким же, если строка (*) удалена (и, очевидно, obj2). Тем не менее obj1 должна быть специализированной версией X, так как строка (*) не имеет к этому никакого отношения.

Но теперь мы ожидаем, что компилятор обнаружит, что некоторый тип может быть потенциально объявлен как B<T>::type, хотя мы никогда этого не делаем. Мы ожидаем, что компилятор проверит все возможные экземпляры шаблонаs, чтобы проверить, нет ли странного typedef в одном из них.

Надеюсь, это проясняет, почему такая специализация не может быть обработана компилятором.


Альтернатива, которая можетhelp

Я полагаю, что ваша проблема может быть решена путем создания класса черт для явного обозначения типов, которые должны обрабатываться особым образом.Примерно так:

template <bool v>
struct boolean_value {
  static const bool value=v;
};

template <typename T>
struct is_my_interesting_type : public boolean_value<false> {};

class MyClass {
  ...
};

template <>
struct is_my_interesting_type<MyClass> : public boolean_value<true> {};

template <typename T, bool special>
class  InternalX {
  ... //generic version of your template X
};

template <typename T>
class InternalX<T,true> {
  ... //special version of your template X
};

template <typename T>
class X : public InternalX<T,is_my_interesting_type<T>::value> {};

Также вам может быть интересно, как это делается в библиотеке буста, в частности Boost.Type_Traits

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...