leesangwon0114

I am Research Engineer. Currently working in KT.

C++Template 3. Template Instantiation#2

06 Aug 2018 » c++

codenuri 강석민 강사 강의 내용기반으로 정리한 내용입니다.

Template Instantiation Technic

Object Generator Idioms 기법
  1. C++17이 나오기 전까지는 클래스 템플릿은 함수 인자를 통해 타입을 추론 할 수 없기 때문에, 클래스 템플릿 사용이 복잡하고 불편하다 -> 함수 템플릿을 만듬

  2. 클래스 템플릿의 객체를 생성하는 함수 템플릿을 사용한다.
    • 함수 템플릿은 함수 인자를 통해 타입을 컴파일러가 추론할 수 있다는 특징을 활용한 기법
  3. make_pair(), make_tuple()등의 make 계열 함수, STL 삽입 반복 자동
template<typename T> void foo(T a) {}

template<typename T, typename U> struct pair
{
    T first;
    U second;
    pair(const T& a, const U& b): first(a), second(b) {}
};

// 함수 템플릿
template<typename T, typename U>
pair<T, U> make_pair(const T& a, const U& b)
{
    return pair<T, U>(a,b);
}

int main() {
    pair<int, double> p(1, 3.4);
    foo(p);

    foo(pair<int, double>(1,3.4));  // 임시객체로 전달...

    foo(pair(1, 3.4)); // C++ 17

    foo(make_pair(1,3.4));
    // foo(tuple<int, double, int>(1, 3.4, 1));
    // foo(make_tuple(1, 3.4,1));
}
Identity 기법
  1. 함수 템플릿 사용시 컴파일러에 의한 타입 추론을 막는 테크닉
  2. 함수 템플릿 사용시 사용자가 반드시 타입을 전달하도록 하고 싶을 때
    • 컴파일러에 의한 타입 추론이 원하지 않은 타입으로 추론되는 경우
template<typename T> struct identity
{
    typedef T type;
};

template<typename T> void foo(T a) {}
template<typename T> void goo(typename identity<T>::type a) {}
                               // T 타입이라 foo랑 같을까?

int main() {

    identity<int>::type n; // int

    foo(3);         // ok 함수템플릿이므로 컴파일러가 추론해서 가능
    foo<int>(3);    // ok

    goo(3);         // identity는 클래스 템플릿이므로 3을 가지고 클래스 템플릿추론 불가(C++17이라도 생성자나 가이드가 없어 추론 불가) -> 컴파일 타임 error

    goo<int>(3);    // ok
}

template instantiation 주의사항

  1. square는 함수가 아닌 함수 템플릿, square 가 함수
#include <iostream>
using namespace std;

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

int main()
{
    // printf("%p\n", &square); // error 템플릿은 틀이니까
    printf("%p\n", &square<int>); // ok 이렇게 적으면 인스턴스화 시킴
    printf("%p\n", static_cast<int(*)int>(&square)); // ok

    // auto p = &square; // error
    auto p1 = &square<int>; // ok
    auto p2 = static_cast<int(*)(int)>(&square); // ok
}


템플릿과 다중파일

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);
}

템플릿은 소스에 제공하는 것이 아니라 헤더에 제공하는 것임(위 처럼하면 error)

template 은 틀이고 cpp은 파일별로 분할해서 컴파일함 Lib.h 만 포함되어 있으니 컴파일러는 헤더만 보고 square의 정의부분이 없어 코드 생성을 못해 error 발생

해결책

선언쪽에 template을 구현해야함

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);
}