Почему следующий код не работает при компиляции с:
$ g ++ temp_main.cpp temp_spec.cpp /tmp/ccirjc3Y.o:temp_spec.cpp:(.text+0x100): множественное определение `my :: say () ' /tmp/ccSo7IVO.o:temp_main.cpp:(.text$_ZN2myILi0EE3sayEv[my::say()]+0x0): сначала определено здесь collect2: ld вернул 1 статус выхода
Я пытаюсь иметь специализацию статической функции только при использовании
параметр 0.
temp_gen.h:
#ifndef temp_gen_h
#define temp_gen_h
#include <iostream>
template<int N>
struct my
{
static void say();
};
template<int N>
void my<N>::say()
{
std::cout << "generic " << N << std::endl;
}
#endif
temp_spec.h:
#ifndef temp_spec_h
#define temp_spec_h
#include <iostream>
#include "temp_gen.h"
template<>
void my<0>::say()
{
std::cout << "specialized " << 0 << std::endl;
}
#endif
temp_spec.cpp:
#include "temp_spec.h"
temp_main.cpp:
#include "temp_gen.h"
int main(int argc, char* argv[])
{
my<0>::say(); //should say "specialized 0"my<1>::say(); //should say "generic 0"}
Изнутри вашего main.cpp
, вы не специализировали класс шаблона, это потому, что вы не включили temp_spec.h
,
Как указал Вон Катон (см. Комментарии), вы должны переместить определение специализированного метода (который больше не является шаблонным методом), чтобы temp_spec.cpp
,
Я думаю (но я не эксперт в этом) вы должны всегда поставить специализацию непосредственно под общим шаблоном (в том же заголовочном файле), потому что всякий раз, когда вы включаете это, вы также хотите, чтобы были определены специализированные, в противном случае вы будете сбиты с толку, когда такие ошибки происходят. Вы можете, однако, просто включить temp_spec.h
на дне temp_gen.h
,
Кроме того, вам не нужны файлы .cpp для заголовков шаблонов, так как никогда не будет никакого кода для компиляции отдельно (классы шаблонов всегда компилируются в другом файле .cpp, который его использует, и я думаю, что дубликаты будут удалены при связывании, в результате чего проблема во время соединения снова, когда в одном случае вы не специализируйся, однажды ты сделал) [Этот абзац применяется только к общему шаблонному классу, а не к (полностью) специализированным классам, так как они требовать некоторый код в их собственном модуле компиляции, см. комментарии и редактирование выше.]
Я считаю, что, поскольку реализация вашей шаблонной специализации находится в заголовке, вам нужно пометить ее inline
поэтому компилятор / компоновщик знает, что вам разрешено нарушать одно правило определения.
Используя стандартную версию n3337 (выделено мной):
14.7.3 Явная специализация [temp.expl.spec]
6 / Если шаблон, шаблон элемента или элемент шаблона класса явно специализированы, то эта специализация должна быть объявлена до первого использования этой специализации, которое вызовет неявную реализацию, в каждой единице перевода в котором такое использование происходит; Диагностика не требуется.
Потому что в main
специализация my<0>::say
не видно, происходит неявное создание экземпляра, и вы в конечном итоге в случае выше: Диагностика не требуется (от компилятора).
Обратите внимание, что специализация может быть объявлена только после того, как ее общий аналог был объявлен.