Частичная специализация шаблона с ошибкой нескольких аргументов шаблона

Когда я использую частичную специализацию шаблона для класса с одним аргументом шаблона, я могу специализировать такой метод:

#include <cstdlib>

template< std::size_t Dim >
class Test
{
public:
  int foo();
};

template< std::size_t Dim >
inline int Test< Dim >::foo()
{
  return 0;
}

template<>
inline int Test< 1 >::foo()
{
  return 1;
}

int main()
{
  Test< 2 > wTest2;
  Test< 1 > wTest1;
  wTest2.foo();
  wTest1.foo();
  return 0;
}

Метод foo специализируется на Dim = 1. Но как только я добавляю аргумент шаблона в свой класс, например:

#include <cstdlib>

template< typename T, std::size_t Dim >
class Test
{
public:
  int foo();
};

template< typename T, std::size_t Dim >
inline int Test< T, Dim >::foo()
{
  return 0;
}

template< typename T >
inline int Test< T, 1 >::foo()
{
  return 1;
}

int main()
{
  Test< double, 2 > wTest2;
  Test< double, 1 > wTest1;
  wTest2.foo();
  wTest1.foo();
  return 0;
}

Компилятор (VS2010) жалуется на следующие ошибки:

1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(20): error C3860: template argument list following class template name must list parameters in the order used in template parameter list
1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(20): error C2995: 'int Test<T,Dim>::foo(void)' : function template has already been defined
1>          c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(7) : see declaration of 'Test<T,Dim>::foo'
1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(20): error C2976: 'Test<T,Dim>' : too few template arguments
1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(26): error C2264: 'Test<T,Dim>::foo' : error in function definition or declaration; function not called
1>          with
1>          [
1>              T=double,
1>              Dim=2
1>          ]
1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(27): error C2264: 'Test<T,Dim>::foo' : error in function definition or declaration; function not called
1>          with
1>          [
1>              T=double,
1>              Dim=1
1>          ]
1>
1>Build FAILED.

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

Если это не поддерживается в C ++, объясните, почему.


person Philippe Cayouette    schedule 24.10.2011    source источник
comment
дурацкий ответ на этот вопрос часто задаваемых вопросов: stackoverflow.com/questions/1501357 /   -  person Johannes Schaub - litb    schedule 25.10.2011
comment
Спасибо, Йоханнес, я часами безуспешно искал такой ответ. При этом мой вопрос немного другой, я спрашиваю, почему это не работает, и пока у меня нет однозначного ответа.   -  person Philippe Cayouette    schedule 25.10.2011


Ответы (2)


Вы не можете частично специализировать функции - это включает функции-члены. Вы можете только частично специализировать весь класс:

template< typename T, std::size_t Dim >
class Test
{
public:
  int foo()
  {
    return 0;
  }
};

template< typename T >
class test< T, 1 >
{
public:
  int foo()
  {
    return 1;
  }
};

(Здесь я определил встроенные функции; в этом, конечно, нет необходимости.)

person Konrad Rudolph    schedule 24.10.2011
comment
Хорошо, пример с одним аргументом шаблона должен называться полной специализацией, а не частичной; и, вероятно, поэтому это работает. Однако я не вижу причин, по которым частичная специализация не поддерживается для функций-членов, вы можете объяснить, почему? Есть ли у компилятора двусмысленность или ограничение? - person Philippe Cayouette; 25.10.2011
comment
@Philippe Я не уверен, почему запрещены частичные шаблоны функций (но то, что они достигают, обычно можно решить с помощью перегрузки). Однако посмотрите ответ Regu, поскольку мое объяснение на самом деле неверно, вы не частично специализируетесь на функциях-членах. Тем не менее, синтаксис, который вы используете, просто недействителен по тонким причинам (вы определяете функцию-член для частично специализированного класса, но вы фактически не специализируете этот класс частично). - person Konrad Rudolph; 25.10.2011
comment
Регу предложил то, что я реализовал в первую очередь, поскольку я не знал трюка с перегрузкой, указанного Йоханнесом Шаубом (stackoverflow.com/questions/1501357/) - person Philippe Cayouette; 25.10.2011


Редактирую, так как я еще не могу оставлять комментарии (50 реп. Хех) ...

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

template< >
inline int Test< int, 2 >::foo()
{...}

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

Проблема в коде Филиппа заключается в том, что мы объявляем шаблон класса, а не шаблон функции. Следовательно, объявление специализации шаблона частичного класса необходимо для того, чтобы определение частичной специализации было законным.

#include <cstdlib>

template< typename T, std::size_t Dim >
class Test
{
public:
    int foo();
};

template < typename T >
class Test < T, 1 >
{
public:
    int foo();
};


template< typename T, std::size_t Dim >
inline int Test< T, Dim >::foo()
{
    return 0;
}

template< typename T >
inline int Test< T, 1 >::foo()
{
    return 1;
}

int main()
{
    Test< double, 2 > wTest2;
    Test< int, 1 > wTest1;
    wTest2.foo();
    wTest1.foo();
    return 0;
}
person regu    schedule 24.10.2011