Объявление специалиста по членству в типовом классе
Когда я специализирую (статическую) функцию-член/константу в классе шаблона, я смущен относительно того, куда должно идти объявление.
Вот пример того, что мне делать, - прямо из ссылка IBM на специализированную специализацию:
=== Пример специализации для членов IBM ===
template<class T> class X {
public:
static T v;
static void f(T);
};
template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }
template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }
int main() {
X<char*> a, b;
X<float> c;
c.f(10); // X<float>::v now set to 20
}
Вопрос в том, как я могу разделить это на файлы header/cpp? Родовая реализация явно находится в заголовке, но как насчет специализации?
Он не может попасть в заголовочный файл, потому что он конкретный, что приводит к множественному определению. Но если он входит в файл .cpp, это код, который вызывает X:: f(), который знает специализацию, или может полагаться на общий X:: f()?
Пока у меня есть специализация только в .cpp, без объявления в заголовке. У меня нет проблем с компиляцией или даже запуском моего кода (на gcc, не помню версию на данный момент), и она ведет себя так, как ожидалось, - признавая специализацию. Но A) Я не уверен, что это правильно, и я хотел бы знать, что есть, и B) моя документация Doxygen выходит из игры и очень вводит в заблуждение (более того, в <забастовке > момент) вопрос).
То, что кажется самым естественным для меня, было бы чем-то вроде этого, объявив специализацию в заголовке и определяя его в .cpp:
=== XClass.hpp ===
#ifndef XCLASS_HPP
#define XCLASS_HPP
template<class T> class X {
public:
static T v;
static void f(T);
};
template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }
/* declaration of specialized functions */
template<> char* X<char*>::v;
template<> void X<float>::f(float arg);
#endif
=== XClass.cpp ===
#include <XClass.hpp>
/* concrete implementation of specialized functions */
template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }
... но я понятия не имею, правильно ли это. Любые идеи?
Ответы
Ответ 1
Обычно вы просто определяете специализации inline
в заголовке, как dirkgently said.
Вы можете определить специализации в отдельных единицах перевода, но если вас беспокоит время компиляции или раздувание кода:
// x.h:
template<class T> struct X {
void f() {}
}
// declare specialization X<int>::f() to exist somewhere:
template<> void X<int>::f();
// translation unit with definition for X<int>::f():
#include "x.h"
template<> void X<int>::f() {
// ...
}
Итак, ваш подход выглядит отлично. Обратите внимание, что вы можете делать это только с помощью полной специализации, поэтому часто это непрактично.
Подробнее см., например, Часто задаваемые вопросы о шаблонах часовых поясов.
Ответ 2
Поместите их все в файл hpp
. Внесите специализации и все, что вы определили вне класса inline
, - которые позаботятся о нескольких определениях.
Ответ 3
Чтобы ответить на один из вопросов: is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?
Если компилятор видит определение, соответствующее его требованиям, он будет использовать его. Иначе он будет генерировать обычные вызовы функций.
В первом фрагменте кода вы предоставляете общее определение для X<T>::f(T arg)
, поэтому компилятор будет создавать экземпляр для любого T
, кроме float
.
Если вы должны опустить общее определение, тогда компилятор будет генерировать вызовы, скажем, X<double>::f(double)
, и компоновщик будет искать определение, которое может закончиться ошибкой компоновщика.
Подводя итог: вы можете иметь все в заголовках, потому что в качестве шаблонов вы не получите несколько определений. Если у вас есть только объявления, вам понадобятся определения в другом месте, чтобы ссылки могли найти позже.