Подтвердить что ты не робот

Почему частичное задание шаблона вложенного класса разрешено, а полное - нет?

    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.С++ не посмел ответить, поэтому я снова помещаю его сюда с благодарностью.

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

Ответ 3

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

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

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

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. Я не смог его скомпилировать с реализацией вне шаблона.