специализация на подмножестве типов в шаблоне C

#c #templates #specialization

#c #шаблоны #специализация

Вопрос:

У меня есть вопрос о специализации шаблонов в 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. Я перепробовал множество различных комбинаций синтаксисов специализации шаблонов (слишком много, чтобы перечислять здесь), и, похоже, ни один из них не компилируется.

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

Майкл

Ответ №1:

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

 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> amp; )
  {
      //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> amp; ) 
  {
      //this function will get executed when C = int
      //so write your code here, for the special case when C = int
  }
};
  

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

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

Комментарии:

1. Спасибо за этот ответ. Думаю, я понимаю, что происходит, и собираюсь это попробовать.

Ответ №2:

Отправка по типу преобразователя, как показывает @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;
};
  

Комментарии:

1. если myClassFuncs::MyFunc обращается к закрытым элементам myClass , то вы должны это сделать friend .

2. @Nawaz -Статические функции-члены могут обращаться к закрытой части объявления класса.

3. @Mahesh: статические функции-члены класса a могут обращаться только к закрытым членам этого класса. Но здесь myClassFuncs класс отличается от myClass .

4. @Nawaz: Верно, я имел в виду этот материал о друзьях, но, кажется, я снова забыл об этом. Отредактировано. Хотя, я вроде как рекламирую здесь плохую практику, да?

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