wielokrotne definiowanie specjalizacji szablonu przy użyciu różnych obiektów

Kiedy używam specjalistycznego szablonu w różnych plikach obiektowych, podczas łączenia pojawia się błąd" definicja wielokrotna". Jedyne rozwiązanie, które znalazłem, polega na użyciu funkcji "inline", ale wydaje się to być jakieś obejście. Jak rozwiązać ten problem bez użycia słowa kluczowego "inline"? Jeśli to niemożliwe, dlaczego?

Oto przykładowy kod:

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

Wreszcie:

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

Jeśli odkomentuję" inline " wewnątrz hello.h, kod zostanie skompilowany i uruchomiony, ale to po prostu wydaje mi się jakimś "obejściem": co jeśli wyspecjalizowana funkcja jest duża i używana wiele razy? Dostanę duży binarny? Jest na to jakiś inny sposób? Jeśli tak, to w jaki sposób? Jeśli nie, to dlaczego?

Próbowałem szukać odpowiedzi, ale wszystko, co dostałem ,to" użyj inline " bez dalszego wyjaśnienia.

Dzięki

Author: FluxLemur, 2010-12-15

3 answers

Intuicyjnie, kiedy w pełni specjalizujesz się w czymś, nie zależy to już od parametru szablonu -- więc jeśli nie tworzysz specjalizacji w linii, musisz umieścić ją w .plik cpp zamiast a .albo złamiesz zasadę jednej definicji, jak mówi David. Zauważ, że w przypadku częściowej specjalizacji szablony nadal zależą od jednego lub więcej parametrów szablonu, więc nadal są one dostępne .plik H.

 91
Author: Stuart Golodetz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-15 00:51:58

Słowo kluczowe inline polega bardziej na informowaniu kompilatora, że symbol będzie obecny w więcej niż jednym pliku obiektowym bez naruszania zasady jednej definicji, niż na faktycznym inliningu, który kompilator może zdecydować, czy to zrobić, czy nie.

Problem, który widzisz jest to, że bez inline, funkcja będzie skompilowana we wszystkich jednostkach tłumaczeniowych, które zawierają nagłówek, naruszając ODR. Dodanie inline jest właściwą drogą. W przeciwnym razie możesz przekazać specjalizacji i zapewnić go w jednej jednostce tłumaczenia, Jak to zrobić z każdej innej funkcji.

 37
Author: David Rodríguez - dribeas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-19 20:04:55

W nagłówku (void Hello<T>::print_hello(T var)) Utworzono jawnie instancję szablonu. Spowoduje to utworzenie wielu definicji. Można go rozwiązać na dwa sposoby:

1) Utwórz instancję w linii.

2) Zadeklaruj instancję w nagłówku, a następnie zaimplementuj ją w cpp.

 16
Author: Crazy Eddie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-15 00:34:35