컴파일러는 자체 인스턴스화 대신 템플릿 전문화를 어떻게 사용하는지 어떻게 알고 있습니까?

StackOverflow https://stackoverflow.com/questions/2058159

  •  20-09-2019
  •  | 
  •  

문제

다음 파일을 고려하십시오.

foo.h

template <typename T>
struct Foo
{
  int foo();
};

template <typename T>
int Foo<T>::foo()
{
  return 6;
}

foo.c

#include "Foo.H"

template <>
int Foo<int>::foo()
{
  return 7;
}

Main.C

#include <iostream>
#include "Foo.H"

using namespace std;

int main()
{
  Foo<int> f;
  cout << f.foo() << endl;
  return 0;
}

컴파일하고 실행하면 7이 인쇄됩니다. 여기서 무슨 일이야? 템플릿은 언제 인스턴스화됩니까? 컴파일러가이를 수행하면 컴파일러가 자체 버전의 FOO를 인스턴스화하지 않는다는 것을 어떻게 알 수 있습니까?

도움이 되었습니까?

해결책

문제는 하나의 정의 규칙을 위반했다는 것입니다. main.c에서는 foo.h를 포함했지만 foo.c는 포함하지 않았습니다 (소스 파일이기 때문에 의미가 있습니다). main.c가 컴파일되면 컴파일러는 foo.c에서 템플릿을 전문화한다는 것을 알지 못하므로 일반 버전 (6)을 사용하고 foo 클래스를 컴파일합니다. 그런 다음 foo.c를 컴파일하면 컴파일 할 수있는 전체 전문화가 있습니다. - 모든 유형이 채워져 있기 때문에 어딘가에 인스턴스화 될 때까지 기다릴 필요가 없습니다 (두 개의 템플릿 매개 변수가 있고 특수화 된 경우에만 해당되지 않습니다). 새롭고 뚜렷한 Foo 클래스.

일반적으로 동일한 것에 대한 여러 정의는 링커 오류를 일으 킵니다. 그러나 템플릿 인스턴스화는 "약한 기호"이므로 여러 정의가 허용됩니다. 링커 모든 정의가 실제로 동일하다고 가정합니다 그런 다음 무작위로 하나를 선택합니다 (아마도 일관되게 첫 번째 또는 마지막 것, 그러나 구현의 우연의 일치로만).

왜 약한 상징을 만드는가? FOO는 여러 소스 파일에서 사용될 수 있고, 각 파일은 개별적으로 컴파일되며, FOO가 컴파일 장치에 사용될 때마다 새로운 인스턴스화가 생성됩니다. 일반적으로 이것들은 중복되므로 버리기는 것이 합리적입니다. 그러나 당신은 한 편집 장치 (foo.c)에서 전문화를 제공 함으로써이 가정을 위반했지만 다른 편집 장치 (main.c)는 아닙니다.

foo.h에서 템플릿 전문화를 선언하면 main.c가 컴파일되면 foo의 인스턴스화를 생성하지 않으므로 프로그램에 하나의 정의 만 존재하는지 확인하십시오.

다른 팁

컴파일러가 FOO를 인스턴스화한다고 생각하지만 연결하면 대신 전문 FOO를 선택합니다.

Main.c를 컴파일 할 때 컴파일러는 전문화에 대해 알지 못합니다. 자체 버전을 생성해야한다고 생각합니다 Foo<int>::foo() 비 전문화 된 템플릿을 기반으로합니다.

그러나 링커는 링크 할 때 Foo<int>::foo() 존재합니다. 따라서 실행 파일을 특수 버전으로 넣습니다.

결국, 컴파일 타임에 그것을 알지 못하더라도 main.c는 특수 버전을 호출합니다. Foo<int>::foo().

템플릿은 템플릿 매개 변수의 모든 조합에 대해 다른 클래스를 생성합니다. 이것은 컴파일 시간에 발생하며 이것이 템플릿이 헤더에있는 이유입니다. int 매개 변수 및 컴파일러 호출을위한 전문화 Foo<int>::foo() 변수의 경우 f. 가상 기능을 재정의하는 것과 같지만 컴파일 시간에 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top