Вызовите неспециализированную версию функции, когда она специализируется на С++?
Скажем, у меня есть шаблон:
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, поскольку он сильно разделяет код.)
Ответы
Ответ 1
Нет. Ваша специализация - единственное определение, которое будет существовать для аргумента типа 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
}
Это похоже на структуру основного использования для частных виртуальных участников. (На самом деле это не так. Но это вдохновило меня на этот ответ.)
Ответ 2
Вы также можете рассмотреть тип, который не является 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);
}
Ответ 3
Да, это на самом деле довольно просто. Вы просто позволяете основной, общей версии вашей функции служить в качестве сквозной функции общего назначения "реализация", которая не становится частично специализированной, тогда вы можете просто вызвать ее из специализированной версии начальной функции по мере необходимости.
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
}
Я думаю, что это ближе к вашим первоначальным намерениям, чем Стив М. отвечает, и это то, что я делаю, когда сталкиваюсь с этой проблемой.