множественное определение специализации шаблона при использовании разных объектов - PullRequest
74 голосов
/ 15 декабря 2010

Когда я использую специализированный шаблон в разных объектных файлах, я получаю ошибку «множественное определение» при компоновке. Единственное решение, которое я нашел, заключается в использовании встроенной функции, но это выглядит как обходной путь. Как решить эту проблему, не используя ключевое слово "inline"? Если это невозможно, почему?

Вот пример кода:

paulo@aeris:~/teste/cpp/redef$ cat hello.h 
#ifndef TEMPLATE_H
#define TEMPLATE_H

#include <iostream>

template <class T>
class Hello
{
public:
    void print_hello(T var);
};

template <class T>
void Hello<T>::print_hello(T var)
{
    std::cout << "Hello generic function " << var << "\n";
}

template <> //inline
void Hello<int>::print_hello(int var)
{
    std::cout << "Hello specialized function " << var << "\n";
}

#endif

paulo@aeris:~/teste/cpp/redef$ cat other.h 
#include <iostream>

void other_func();

paulo@aeris:~/teste/cpp/redef$ cat other.c 
#include "other.h"

#include "hello.h"

void other_func()
{
    Hello<char> hc;
    Hello<int> hi;

    hc.print_hello('a');
    hi.print_hello(1);
}

paulo@aeris:~/teste/cpp/redef$ cat main.c 
#include "hello.h"

#include "other.h"

int main()
{
    Hello<char> hc;
    Hello<int> hi;

    hc.print_hello('a');
    hi.print_hello(1);

    other_func();

    return 0;
}

paulo@aeris:~/teste/cpp/redef$ cat Makefile
all:
    g++ -c other.c -o other.o -Wall -Wextra
    g++ main.c other.o -o main -Wall -Wextra

Наконец:

paulo@aeris:~/teste/cpp/redef$ make
g++ -c other.c -o other.o -Wall -Wextra
g++ main.c other.o -o main -Wall -Wextra
other.o: In function `Hello<int>::print_hello(int)':
other.c:(.text+0x0): multiple definition of `Hello<int>::print_hello(int)'
/tmp/cc0dZS9l.o:main.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: ** [all] Erro 1

Если я раскомментирую «inline» внутри hello.h, код скомпилируется и запустится, но для меня это просто своего рода «обходной путь»: что если специализированная функция большая и используется много раз? Получу ли я большой двоичный файл? Есть ли другой способ сделать это? Если да, то как? Если нет, то почему?

Я пытался искать ответы, но все, что я получил, было «использовать inline» без каких-либо дополнительных объяснений.

Спасибо

Ответы [ 3 ]

102 голосов
/ 15 декабря 2010

Интуитивно понятно, что когда вы что-то полностью специализируете, это больше не зависит от параметра шаблона - поэтому, если вы не сделаете специализацию встроенной, вам нужно поместить ее в файл .cpp вместо .h или завершитьнарушая одно правило определения, как говорит Дэвид.Обратите внимание, что при частичной специализации шаблонов частичная специализация по-прежнему зависит от одного или нескольких параметров шаблона, поэтому они по-прежнему сохраняются в файле .h.

41 голосов
/ 15 декабря 2010

Ключевое слово inline больше говорит о том, что компилятор указывает, что символ будет присутствовать в нескольких объектных файлах без нарушения правила One Definition, а не о фактической вставке, которую компилятор может решить или не делать.1002 *

Проблема, с которой вы сталкиваетесь, заключается в том, что без встроенной функции функция будет скомпилирована во всех единицах перевода, которые включают заголовок, что нарушает ODR.Добавление inline - правильный путь.В противном случае вы можете заранее объявить специализацию и предоставить ее в одной единице перевода, как вы это сделали бы с любой другой функцией.

19 голосов
/ 15 декабря 2010

Вы явно создали экземпляр шаблона в своем заголовке (void Hello<T>::print_hello(T var)). Это создаст несколько определений. Вы можете решить это двумя способами:

1) Сделайте свою инстанцию ​​встроенной.

2) Объявите экземпляр в заголовке и затем внедрите его в cpp.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...