специализирующийся на подмножестве типов в шаблоне C ++ - PullRequest
3 голосов
/ 03 июня 2011

У меня есть вопрос о специализации шаблонов в C ++, и я надеюсь, что кто-то здесь может помочь. У меня есть класс, который имеет 3 параметра шаблона:

template<class A, class B, class C>
class myClass {

public:
  void myFunc();
};

Я хочу написать несколько версий myFunc, которые специализируются, скажем, на типе C, но являются общими для типов A и B. Поэтому я НЕ хочу полностью шаблонную функцию, подобную этой:

template<class A, class B, class C>
void myClass<A, B, C>::myFunc()
{
  // function code here
}

и я НЕ хочу полностью специализированную функцию, подобную этой

void myClass<int, int, int>::myFunc()
{
  // code goes here
}

Вместо этого я хочу сделать что-то похожее на

template<class A, class B>
void myClass<A, B, int>::myFunc()
{
  // code goes here
}

Идея состоит в том, что если тип класса C равен int, я бы назвал одну версию myFunc (), а если тип класса C - double, я бы назвал другую версию myFunc. Я перепробовал множество различных комбинаций синтаксисов специализации шаблонов (их слишком много, чтобы перечислять их здесь), но ни один из них не компилируется.

Может ли кто-нибудь указать мне правильное направление здесь? Заранее благодарим за помощь.

Michael

Ответы [ 2 ]

6 голосов
/ 03 июня 2011

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

template<class A, class B, class C>
class myClass 
{
   //resolver doesn't need to define anything in it!
   template<class> struct resolver {}; //empty, yet powerful!
public:
  void myFunc() 
  {
       doFun(resolver<C>());
  }

  //this is a function template
  template<typename X>
  void doFun(const resolver<X> & )
  {
      //this function will get executed when C is other than int
      //so write your code here, for the general case
  }

  //this is an overload, not a specialization of the above function template!
  void doFun(const resolver<int> & ) 
  {
      //this function will get executed when C = int
      //so write your code here, for the special case when C = int
  }
};

Обратите внимание на важный момент: doFun(const resolve<int>& ) - перегруженная функция, а не специализация функциишаблон.Вы не можете специализировать шаблон функции-члена без , специализирующего шаблон класса включения.

Прочитайте эти статьи:

0 голосов
/ 03 июня 2011

Диспетчер по типу резольвера, как показывает @Nawaz, ИМХО - лучший способ.Другой вариант - переместить реальную реализацию этой функции за пределы класса, внутри собственной структуры, сделать ее статической и частично специализировать структуру.В классе, назовите это.Конечно, если он обращается к закрытым частям myClass, вам нужно сделать его friend:

template<class A, class B, class C>
class myClass;

template<class A, class B, class C>
struct myClassFuncs{
  typedef myClass<A,B,C> class_type;

  static void myFunc(class_type* self){
    // generic for everything ...
  }
};

template<class A, class B>
struct myClassFuncs<A,B,int>{
  typedef myClass<A,B,int> class_type;

  static void myFunc(class_type* self){
    // specialized on C == int ...
  }
};

// and so on ...

template<class A, class B, class C>
class myClass{
  typedef myClassFuncs<A,B,C> func_holder;
  friend class func_holder;
public:
  void myFunc(){
    func_holder::myFunc(this);
  }
};

Хотя это приводит к множеству обёрток в классе и специализированных версиях ...

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

template<class A, class B, class C>
class myClass;

template<class A, class B, class C>
class myClass_myFunc{
  typedef myClass<A,B,C> class_type;
  class_type* const _self;

public:
  myClass_myFunc(class_type* self)
    : _self(self)
  {}

  void operator() const{
    // generic logic here
  }
};

template<class A, class B>
class myClass_myFunc<A,B,int>{
  typedef myClass<A,B,int> class_type;
  class_type* const _self;

public:
  myClass_myFunc(class_type* self)
    : _self(self)
  {}

  void operator() const{
    // specialized logic here
  }
};

template<class A, class B, class C>
class myClass{
  friend class myClass_myFunc<A,B,C>;
public:
  myClass()
    : myFunc(this)
  {}

  const myClass_myFunc<A,B,C> myFunc;
};
...