Когда я специализирую (статическую) функцию членства / постоянный в шаблонном классе, я смущен как, туда, где объявление предназначено для движения.
Вот пример того, что я, что сделать - yoinked непосредственно из ссылки IBM на шаблонной специализации:
=== Пример специализации члена IBM ===
template class X {
public:
static T v;
static void f(T);
};
template T X::v = 0;
template void X::f(T arg) { v = arg; }
template<> char* X::v = "Hello";
template<> void X::f(float arg) { v = arg * 2; }
int main() {
X a, b;
X c;
c.f(10); // X::v now set to 20
}
Вопрос, как я делю это на header/cpp файлы? Универсальная реализация находится, очевидно, в заголовке, но что относительно специализации?
Это не может войти в заголовочный файл, потому что это конкретно, ведя к повторному определению. Но если это входит в .cpp файл, код, который звонит X:: f () знающий о специализации, или мог бы он полагаться на дженерик X:: f ()?
До сих пор у меня есть специализация в .cpp только без объявления в заголовке. Я не испытываю затруднения при компиляции или даже выполнении моего кода (на gcc, не помните версию в данный момент), и это ведет себя как ожидалось - распознавание специализации. Но A) я не уверен, что это корректно, и я хотел бы знать то, что и B) моя документация Doxygen выходит wonky и очень вводящий в заблуждение (больше на том через мгновение более поздний вопрос).
То, что кажется самым естественным для меня, было бы чем-то вроде этого, объявив специализацию в заголовке и определив его в .cpp:
=== XClass.hpp ===
#ifndef XCLASS_HPP
#define XCLASS_HPP
template class X {
public:
static T v;
static void f(T);
};
template T X::v = 0;
template void X::f(T arg) { v = arg; }
/* declaration of specialized functions */
template<> char* X::v;
template<> void X::f(float arg);
#endif
=== XClass.cpp ===
#include
/* concrete implementation of specialized functions */
template<> char* X::v = "Hello";
template<> void X::f(float arg) { v = arg * 2; }
... но я понятия не имею, корректно ли это. Какие-либо идеи?
Обычно вы просто определяете специализации inline
в заголовке, как сказал dirkgently.
Однако вы можете определить специализации в отдельных единицах трансляции, если вас беспокоит время компиляции или раздутость кода:
// 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() {
// ...
}
Так что да, ваш подход выглядит нормально. Обратите внимание, что это можно сделать только с полными специализациями, поэтому часто это непрактично.
Подробнее см. например, Comeaus template FAQ.
Чтобы ответить на один из ваших вопросов: - это код, который вызывает X :: f () с учетом специализации, или он может полагаться на общий X :: f ()?
Если компилятор видит определение, которое соответствует его требованиям, тогда он будет его использовать. В противном случае он будет генерировать обычные вызовы функций.
В первом фрагменте кода вы предоставляете общее определение для X
, поэтому компилятор создаст его экземпляр для любого T
, кроме поплавок
.
Если вы опустите общее определение, то компилятор сгенерирует вызовы, скажем, X
, и компоновщик будет искать определение, которое может закончиться с ошибкой компоновщика.
Подводя итог: у вас может быть все в заголовках, потому что в качестве шаблонов вы не получите несколько определений. Если у вас есть только объявления, вам понадобятся определения в другом месте, чтобы компоновщик нашел их позже.
Поместите их все в hpp
файл. Сделайте специализации и все, что вы определяете вне класса inline
- это поможет справиться с множественными определениями.