반응형
  • 함수와 템플릿
    • square는 함수가 아닌 함수 템플릿, square<int>가 함수
template<typename T> T square(T a)
{
    return a * a;
}

int main()
{
    printf("%p\n", &square); // 함수 템플릿의 주소 출력 error
    printf("%p\n", &square<int>); // int 버전 함수 주소 출력 ok
    printf("%p\n", static_cast<int(*)(int)>(&square)); // int 버전 함수로 캐스팅후 주소 출력 ok

    auto p = &square; // 함수 템플릿 주소는 담을 수 없으므로 error
    auto p = &square<int>; // int 버전 함수 주소 담기 ok
    auto p = static_cast<int(*)(int)>(&square); // int 버전 함수 주소 담기 ok
}

 

  • 템플릿의 구현부는 항상 헤더파일에 함께 제공하여야 함
    • 아래와 같이 함수 템플릿을 헤더와 소스파일로 분리하면 main에서 square 호출 시 실제 Lib.h 헤더파일만 참고하므로 템플릿을 기반으로 실제 int형 함수 생성이 필요한데 생성할 구현부 확인이 불가능하여 에러 발생
// 함수 템플릿을 선언과 구현부를 헤더와 소스파일로 분리한 잘못 구현한 예
////////////////////////////////////////
// Lib.h
int add(int a, int b);
template<typename T> T square(T a);
////////////////////////////////////////

////////////////////////////////////////
// Lib.cpp
int add(int a, int b) 
{
    return a + b;
}

template<typename T> T square(T a)
{
    return a * a;
}
////////////////////////////////////////

////////////////////////////////////////
// main.cpp
#include "Lib.h"
int main()
{
    add(1, 2);
    square(3);
}
////////////////////////////////////////
// 함수 템플릿을 헤더 파일로 모두 제공한 예
////////////////////////////////////////
// Lib.h
int add(int a, int b);
template<typename T> T square(T a)
{
    return a * a;
}
////////////////////////////////////////

////////////////////////////////////////
// Lib.cpp
int add(int a, int b) 
{
    return a + b;
}
////////////////////////////////////////

////////////////////////////////////////
// main.cpp
#include "Lib.h"
int main()
{
    add(1, 2);
    square(3);
}
////////////////////////////////////////
반응형

반응형

Template Instantiation

  • 컴파일러가 함수(클래스) 틀(Template)로 부터 실제 C++ 함수(클래스)를 만들어 내는 과정
template<typename T>
T square(T a) // template 기준 int squre(int a), double square(double a) 실제 함수를 만드는 과정
{
    return a * a;
}

int main()
{
    square(3);
}

 

  • 명시적 인스턴스화(Explicit Instantiation)
    • 템플릿을 사용해서 특정 타입의 함수(클래스)를 생성해 달라고 명시적으로 지시하는 것
    • 함수/클래스 선언과 유사한 모양으로 작성
template<typename T> class Test
{
public:
    void foo() {}
    void goo() {}
};
template class Test<int>; // 명시적 인스턴스화(클래스 템플릿), foo, goo 모두 인스턴스화
template void Test<int>::foo(); // 명시적 인스턴스화(클래스 템플릿), foo 부분 인스턴스화

template<typename T> T square(T a)
{
    return a * a;
}
template int square<int>(int); // 명시적 인스턴스화(함수 템플릿)
template int square<>(int); // 명시적 인스턴스화(템플릿) 축약 표현
template int square(int); // 명시적 인스턴스화(템플릿) 축약 표현

int main()
{
}

 

  • 암시적 인스턴스화(Implicit Instantiation)
    • 명시적 인스턴스화를 하지 않고 템플릿을 사용하는 경우, 암시적으로 인스턴스화가 발생함
    • 사용 방법
      • 사용자가 타입을 직접 전달하는 방법
      • 함수 인자를 통해서 컴파일러가 타입을 추론하는 방법(template argument type deduction)
      • 클래스 생성자를 통한 컴파일러 타입 추론하는 방법(class template type deduction, C++17이상)
    • 클래스 템플릿의 경우 사용하지 않는 멤버 함수는 인스턴스화 되지 않음(lazy instantiation)
template<typename T> class Test
{
public:
    void foo() {}
    void goo() {}
};
//template class Test<int>; // 명시적 인스턴스화(클래스 템플릿), foo, goo 모두 인스턴스화

template<typename T> T square(T a)
{
    return a * a;
}
//template int square<int>(int); // 명시적 인스턴스화(함수 템플릿)

int main()
{
    int n1 = square(3); // 암시적 인스턴스화(인자를 통한 컴파일러 타입 추론)
    int n2 = square<int>(3); //암시적 인스턴스화

    Test<int> t1; // 암시적 인스턴스화(클래스)
    t1.foo(); // Test 클래스의 foo 멤버함수만 사용하므로 foo 멤버함수만 인스턴스화됨(goo x)
}

 

  • 어셈블리 코드 확인
    • cl file.cpp /FAs -> file.asm 파일 생성
    • g++ file.cpp -S -> file.s 파일 생성
  • 컴파일러 옵션 사용 g++, clang++(중간 언어로 확인 가능)
    • g++ -fdump-tree-original file.cpp -> file.cpp.003t.original
    • clang++ -Xclang -ast-print -fsyntax-only file.cpp
반응형

+ Recent posts