Извикване на неспециализираната версия на функция, когато я специализирате в C++?

Да кажем, че имам шаблонен клас:

template <typename T>
class foo {
  void do_someting(T obj) {
    // do something generic...
  }
};

и искам да специализирам do_something, но в него искам да извикам "нормалната" функция do_something:

template<>
void foo<MyObj>::do_something(MyObj obj) {
  // do something specific...
  // and ALSO do something generic!
}

има ли начин да се препратя към нормалната версия на do_something в моята специализирана функция? Или просто трябва да копирам кода?

(Знам, че мога да преработя foo по такъв начин, че да нямам точно този проблем, но както се случва, не мога наистина да модифицирам „истинското“ foo, тъй като това е силно споделен код.)


person Jacob B    schedule 04.11.2010    source източник
comment
Няма нормална версия на do_something за типа MyObj - целият ефект от специализацията на шаблона е да замени екземпляра, който бихте получили от основния шаблон, с класа/функцията, които дефинирате в специализацията .   -  person Steve Jessop    schedule 04.11.2010
comment
Добре, но компилаторът знае за кода във foo‹T›::do_something, няма причина да не ми позволи да се позова на него по някакъв начин. Напълно съм готов да повярвам, че тази функция на езика просто не съществува, но --- това се опитвам да открия.   -  person Jacob B    schedule 04.11.2010
comment
@Steve Townsend -- това е друг въпрос. Това е въпросът как можете да имате клас с някои специализирани функции и някои неспециализирани функции.   -  person Jacob B    schedule 04.11.2010
comment
няма причина да не ми позволи да се позова на него по някакъв начин - ако шаблоните бяха дефинирани по коренно различен начин, нямаше да има причина. Както е, foo<MyObj> е клас и има функция do_something и тази функция се дефинира от специализацията. Ако базовият шаблон foo беше инстанциран с параметър MyObj, резултатът би бил друг клас, също foo<MyObj>, който не е разрешен, и това е препятствието. Предполагам, че ако езикът по някакъв начин ви позволи да създадете базовия шаблон с друго име, може да сте добре, но няма такъв късмет.   -  person Steve Jessop    schedule 04.11.2010


Отговори (3)


Не. Вашата специализация е единствената дефиниция, която ще съществува за аргумента тип MyObj. Но помислете за модифициране на шаблона foo по този начин, който ще бъде прозрачен за текущите потребители на шаблона:

template<typename T>
class foo {
  void prelude(T &obj){ // choose a better name
    /* do nothing */
  }
  void do_something(T obj){
    prelude(obj);
    // do something generic...
  }
};

След това дефинирайте специализация за прелюдията:

template<>
void foo<MyObj>::prelude(MyObj &obj){
  // do something specific
}

Това е донякъде подобно по структура на случая на основна употреба за частни виртуални членове. (Донякъде. Не съвсем. Но това ме вдъхнови в този отговор.)

person Steve M    schedule 04.11.2010
comment
това наистина изглежда като аналогия със свят на шаблон за NVI на Sutter! - person d.Candela; 02.08.2017

Можете също така да помислите за тип, който не е MyObj, но имплицитно се преобразува в него, но най-добрият начин би бил да се преработи и може би да се извлече общото генерично нещо.

#include <iostream>
#include <boost/ref.hpp>
typedef int MyObj;


template <typename T>
struct foo {
  void do_something(T obj) {
    // do something generic...
    std::cout << "generic " << obj << '\n';
  }
};

template<>
void foo<MyObj>::do_something(MyObj obj) {
  // do something specific...
  std::cout << "special " << obj << '\n';
  // and ALSO do something generic!
  foo<boost::reference_wrapper<MyObj> >().do_something(boost::ref(obj));
}

int main()
{
    foo<int> f;
    f.do_something(10);
}
person UncleBens    schedule 04.11.2010

Да, това всъщност е съвсем просто. Просто оставяте основната, обща версия на вашата функция да служи като преминаване към обща функция за „внедряване“, която не става частично специализирана, тогава можете просто да я извикате от специализираната версия на първоначалната функция според нуждите.

template <typename T>
class foo 
{
  void do_something(T obj) 
  {
     do_something_impl(obj);
  }

  void do_something_impl(T obj)
  {
    // do something generic...
  }
};

Сега специализацията може да извика генеричната версия без проблем:

template<>
void foo<MyObj>::do_something(MyObj obj) 
{
  // do something specific...
  do_something_impl(obj); //The generic part
}

Мисля, че това е по-близо до първоначалните ви намерения, отколкото отговора на Стив М., и това е, което правя, когато се сблъскам с този проблем.

person Matt Phillips    schedule 08.06.2012