Почему частичная специализация вложенного шаблона класса допускается, а полная - нет? - PullRequest
42 голосов
/ 29 марта 2010
    template<int x> struct A {                                                                                                    
        template<int y> struct B {};.                                                                                             
        template<int y, int unused> struct C {};                                                                                  
    };                                                                                                                            

    template<int x> template<> 
    struct A<x>::B<x> {}; // error: enclosing class templates are not explicitly specialized

    template<int x> template<int unused> 
    struct A<x>::C<x, unused> {}; // ok

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

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

К сожалению, никто на comp.std.c ++ не осмелился ответить, поэтому я снова выкладываю его здесь с наградой.

Примечание: мне нужна эта функция для рекурсивных шаблонов внутреннего класса для набора внешнего класса, а специализация внутреннего параметра зависит от параметра внешнего шаблона.

Ответы [ 4 ]

27 голосов
/ 29 марта 2010

Я предполагаю, почему это происходит: полные специализации больше не являются "шаблонными классами / функциями", они являются "реальными" классами / методами и имеют реальные (видимые линкером) символы. Но для полностью специализированного шаблона внутри частично специализированного это было бы неверно. Вероятно, это решение было принято просто для того, чтобы упростить жизнь создателям компиляторов (и усложнить жизнь программистам в процессе: P).

8 голосов
/ 29 марта 2010

Стандарт C ++ явно запрещает полную специализацию классов-членов в первом случае. Согласно 14.7.3 / 18:

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

7 голосов
/ 29 марта 2010

Вы можете обойти это поведение, делегировав реальную работу другой структуре:

namespace detail
{
  template <class T, class U>
  struct InnerImpl {};
}

template <class T>
struct Outer
{
  template <class U>
  struct Inner: detail::InnerImpl<T,U>
  {
  };
};

Теперь вы можете специализироваться InnerImpl, как вы хотите

4 голосов
/ 29 марта 2010

Подкрепляя аргумент Вирджила (он был быстрее, чем я написал то же обоснование), рассмотрите это:

template<typename T1>
class TOuter
  {
  public:
    template<typename T2>
    class TInner
      {
      public:
        T1 m_1;
        T2 m_2;
      };
  };

template<typename T1>
template<>
class TOuter<T1>::TInner<float>
  {
  public:
    T1    m_1;
    float m_2;
 };

Является ли TInner полностью специализированным или частично специализированным из-за T1?

Edit:

После рассмотрения некоторых других комментариев - кажется, что вы хотите иметь полную специализацию, основанную на параметре шаблона во внешнем классе. Если вы вкладываете реализацию внутреннего класса, это похоже на работу в Visual Studio 2005:

template<typename T1>
class TOuter
  {
  public:
    template<typename T2>
    class TInner
      {
      public:
        std::string DoSomething() { return "Inner - general"; }
        T2 m_2;
      };

    template<>
    class TInner<T1>
      {
      public:
        std::string DoSomething() { return "Inner - special"; }
        T1 m_1;
      };
  };

TOuter :: TInner будет правильно специализация TInner. Я не смог заставить его скомпилировать с реализацией вне шаблона.

...