다른 개체를 사용할 때 템플릿 전문화의 다중 정의
다른 개체 파일에서 특수 템플릿을 사용하면 연결할 때 "다중 정의"오류가 발생합니다. 내가 찾은 유일한 해결책은 "인라인"기능을 사용하는 것이지만 일부 해결 방법처럼 보입니다. "인라인"키워드를 사용하지 않고 어떻게 해결합니까? 가능하지 않다면 왜?
다음은 예제 코드입니다.
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
hello.h 내부의 "인라인"주석을 제거하면 코드가 컴파일되고 실행되지만 일종의 "해결 방법"처럼 보입니다. 특수 함수가 크고 여러 번 사용되면 어떻게됩니까? 큰 바이너리를 얻을 수 있습니까? 이 작업을 수행하는 다른 방법이 있습니까? 그렇다면 어떻게? 그렇지 않다면 왜?
답을 찾아 보려고했지만 추가 설명없이 "인라인으로 사용"하는 것이 전부였습니다.
감사
Intuitively, when you fully specialize something, it doesn't depend on a template parameter any more -- so unless you make the specialization inline, you need to put it in a .cpp file instead of a .h or you end up violating the one definition rule as David says. Note that when you partially specialize templates, the partial specializations do still depend on one or more template parameters, so they still go in a .h file.
The keyword inline
is more about telling the compiler that the symbol will be present in more than one object file without violating the One Definition Rule than about actual inlining, which the compiler can decide to do or not to do.
The problem you are seeing is that without the inline, the function will be compiled in all translation units that include the header, violating the ODR. Adding inline
there is the right way to go. Otherwise, you can forward declare the specialization and provide it in a single translation unit, as you would do with any other function.
You've explicitly instantiated a template in your header (void Hello<T>::print_hello(T var)
). This will create multiple definitions. You can solve it in two ways:
1) Make your instantiation inline.
2) Declare the instantiation in a header and then implement it in a cpp.
Here is some piece of C++11 standard related to this issue:
An explicit specialization of a function template is inline only if it is declared with the inline specifier or defined as deleted, and independently of whether its function template is inline. [ Example:
template void f(T) { /* ... / } template inline T g(T) { / ... */ }
template<> inline void f<>(int) { /* ... / } // OK: inline template<> int g<>(int) { / ... */ } // OK: not inline — end example ]
So if you make some explicit(aka full) specializations of templates in *.h
file, then you will still need inline
to help you get rid of the violation of ODR.
'Nice programing' 카테고리의 다른 글
LINQ를 사용하여 사전을 필터링하고 동일한 유형의 사전으로 반환하는 방법 (0) | 2020.10.18 |
---|---|
Java 필터에서 요청 URL을 얻으려면 어떻게해야합니까? (0) | 2020.10.18 |
Ruby on Rails의 정적 페이지 (0) | 2020.10.18 |
내 MVC 애플리케이션에 대한 서비스 계층을 생성합니까? (0) | 2020.10.18 |
uitabbarcontroller를 숨기는 방법 (0) | 2020.10.17 |