Специализация шаблона для статической функции при компиляции с g ++

Почему следующий код не работает при компиляции с:

$ 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"}

3

Решение

Изнутри вашего main.cpp, вы не специализировали класс шаблона, это потому, что вы не включили temp_spec.h,

Как указал Вон Катон (см. Комментарии), вы должны переместить определение специализированного метода (который больше не является шаблонным методом), чтобы temp_spec.cpp,

Я думаю (но я не эксперт в этом) вы должны всегда поставить специализацию непосредственно под общим шаблоном (в том же заголовочном файле), потому что всякий раз, когда вы включаете это, вы также хотите, чтобы были определены специализированные, в противном случае вы будете сбиты с толку, когда такие ошибки происходят. Вы можете, однако, просто включить temp_spec.h на дне temp_gen.h,

Кроме того, вам не нужны файлы .cpp для заголовков шаблонов, так как никогда не будет никакого кода для компиляции отдельно (классы шаблонов всегда компилируются в другом файле .cpp, который его использует, и я думаю, что дубликаты будут удалены при связывании, в результате чего проблема во время соединения снова, когда в одном случае вы не специализируйся, однажды ты сделал) [Этот абзац применяется только к общему шаблонному классу, а не к (полностью) специализированным классам, так как они требовать некоторый код в их собственном модуле компиляции, см. комментарии и редактирование выше.]

2

Другие решения

Я считаю, что, поскольку реализация вашей шаблонной специализации находится в заголовке, вам нужно пометить ее inline поэтому компилятор / компоновщик знает, что вам разрешено нарушать одно правило определения.

2

Используя стандартную версию n3337 (выделено мной):

14.7.3 Явная специализация [temp.expl.spec]

6 / Если шаблон, шаблон элемента или элемент шаблона класса явно специализированы, то эта специализация должна быть объявлена ​​до первого использования этой специализации, которое вызовет неявную реализацию, в каждой единице перевода в котором такое использование происходит; Диагностика не требуется.

Потому что в main специализация my<0>::say не видно, происходит неявное создание экземпляра, и вы в конечном итоге в случае выше: Диагностика не требуется (от компилятора).

Обратите внимание, что специализация может быть объявлена ​​только после того, как ее общий аналог был объявлен.

1
По вопросам рекламы [email protected]