ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [template] 함수 템플릿(function template)
    개발/C·C++ 2021. 4. 30. 20:29

    클래스 자체는 객체가 아니듯이 함수 템플릿은 함수가 아닙니다. 함수를 만들어내는 형판 같은 것입니다. template이라는 키워드는 일반화 프로그래밍을 하게 해줍니다. 영어로는 generic programming이라고 합니다. 객체 지향을 명확하게 몇 가지 문장으로 정의하기 어렵듯이 일반화 프로그래밍도 비슷합니다. 좁은 범위에서는, 특정 타입에 얽매이고 다양한 타입에 대응할 수 있는 프로그램을 작성하는 것, 정도로 생각할 수 있습니다. 다음 예제에서 함수 템플릿을 확인해보겠습니다.

    template<typename T>
    void swap(T& x, T& y)
    {
        T temp = x;
        x = y;
        y = temp;
    }
    
    int main()
    {
        int x = 20, y = 30;
        //swap<int>(x, y) // explicitly(int, int)
        swap(x, y)        // implicitly(int, int)
        double dx = 20.123, dy = 30.456;
        swap(x, y)        // implicitly(double, double)
    }

    역할과 이름이 같은데 인수를 달리 받아서 함수를 작성해야 한다면 오버로딩을 사용하면 됩니다. 하지만 오버로딩은 코드가 중복되며 일일이 함수를 정의해줘야 하는 단점이 있습니다. 함수 템플릿을 사용한다고 해서 오버로딩으로 함수 템플릿을 정의할 일이 아예 사라지는 건 아닙니다. 인수의 타입이 달리해야 할 때는 함수 템플릿을 그에 맞게 만들어야 합니다. 함수 템플릿을 이용하면 중복 코드를 줄일 수 있습니다. 여러 타입에 대해 소수의 템플릿으로 대응할 수 있습니다(위의 예제는 인수로 넘기는 데이터의 타입이 동일한 경우로 한정했습니다).

     

    <typename T>에서 typename 키워드는 이름에서 알 수 있듯 타입을 지정합니다. Ttypename 키워드를 사용해 선언한 타입입니다. 템플릿의 파라미터는 데이터가 아니라 타입인 것입니다. <>를 통해 전달합니다. swap<int>(x, y)처럼 명시적으로 타입을 전달해도 되지만 swap(x, y)처럼 전달하지 않아도 됩니다. 함수 내부에서 파라미터를 통해 타입을 추론할 수 있기 때문입니다. 정수를 인수로 넘기면 typename로 선언한 T의 타입이 int로 결정됩니다.

     

    함수 템플릿은 함수가 아니기 때문에 호출하지 않으면 코드가 생성되지 않습니다. instantiating이 일어나지 않습니다. 함수를 호출해줘야 인스턴스화가 이뤄집니다. 이를 구체화라고도 합니다. 함수를 호출하지 않고 구체화할 수 있는 방법이 있습니다. 위의 예제를 활용한 아래의 예제에서 확인해보겠습니다.

    template<typename T>
    void swap(T& x, T& y)
    {
        T temp = x;
        x = y;
        y = temp;
    }
    
    template void swap<int>(int&, int&); // function template instantiating
    
    int main()
    {}

    main 함수에서 함수를 호출하지 않았지만 int형에 대해서 swap 함수는 구체화가 됩니다. 이런 방법의 구체화는 클래스 템플릿에서도 마찬가지입니다. 호출하거나 객체를 만들지 않아도 해당하는 코드가 만들어집니다. 함수를 호출하면 구체화가 이뤄지는데 왜 위와 같은 방식이 필요할까요. 이 방법은 배포를 위해 템플릿을 이용하는 라이브러리(.lib)를 만들 때 유용합니다. 인스턴스화 되지 않은 템플릿 정의는 목적 파일(.obj)로 생성되지 않으니까요. 그리고 심지어 여러 모듈에서 동일한 인스턴스화가 일어나도 오직 하나의 인스턴스만 만들어집니다.

     

    만약 템플릿 함수를 선언과 정의를 분리해 사용하고자 한다면 템플릿 함수를 헤더 파일에서 선언과 동시에 정의를 하거나, 헤더에는 선언만 남기고 정의부가 있는 cpp 파일에서 위와 같은 구체화 코드를 넣어주면 됩니다. 구체화 코드를 헤더에 넣는 것보다는 정의부에 넣어 숨기는 것이 더 낫다고 판단됩니다.

     

    출처>

    docs.microsoft.com/en-us/cpp/cpp/explicit-instantiation?view=msvc-160

    docs.microsoft.com/en-us/cpp/cpp/function-template-instantiation?view=msvc-160

    stackoverflow.com/questions/2351148/explicit-template-instantiation-when-is-it-used

    댓글

Designed by Tistory.