Объявление специализации члена класса шаблона - PullRequest
13 голосов
/ 23 марта 2010

Когда я специализирую (статическую) функцию-член / константу в шаблонном классе, я не понимаю, куда должно идти объявление.

Вот пример того, что я должен делать - вы обратились непосредственно от Справка 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, не помню версию на данный момент), и он ведет себя как ожидалось - с учетом специализации.Но А) Я не уверен, что это правильно, и я хотел бы знать, что есть, и Б) моя документация по 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; }

... но я понятия не имею, верно ли это.Есть идеи?

Ответы [ 3 ]

10 голосов
/ 23 марта 2010

Обычно вы просто определяете специализации inline в заголовке, как указано прямо.

Вы можете определить специализации в отдельных единицах перевода, хотя, если вас беспокоит время компиляции или раздувание кода:

// 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() {
    // ...
}

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

Подробнее см., Например, FAQ по шаблонам Comeaus .

4 голосов
/ 23 марта 2010

Поместите их все в файл hpp.Создайте специализации и все, что вы определяете вне класса inline - это позаботится о нескольких определениях.

1 голос
/ 23 марта 2010

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

Подводя итог: у вас может быть все в заголовках, потому что в качестве шаблонов вы не получите несколько определений. Если у вас есть только объявления, вам понадобятся определения в другом месте, чтобы компоновщик мог их найти позже.

...