문제

헤더에 인라인 대신 CPP 파일에 저장하고 싶은 템플릿 코드가 있습니다.어떤 템플릿 유형이 사용될지 아는 한 이 작업을 수행할 수 있다는 것을 알고 있습니다.예를 들어:

.h 파일

class foo
{
public:
    template <typename T>
    void do(const T& t);
};

.cpp 파일

template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);

마지막 두 줄을 참고하세요. foo::do 템플릿 함수는 int 및 std::strings에만 사용되므로 이러한 정의는 앱이 연결된다는 의미입니다.

내 질문은 - 이것이 불쾌한 해킹입니까, 아니면 다른 컴파일러/링커에서도 작동합니까?현재는 이 코드를 VS2008에서만 사용하고 있지만 다른 환경으로 이식하고 싶습니다.

도움이 되었습니까?

해결책

설명하는 문제는 헤더에 템플릿을 정의하거나 위에서 설명한 접근 방식을 통해 해결할 수 있습니다.

다음 내용을 읽어 보시기 바랍니다. C++ FAQ 라이트:

그들은 이러한 (및 기타) 템플릿 문제에 대해 자세히 설명합니다.

다른 팁

명시적 템플릿 전문화(또는 적어도 VS2008에서는)에 대한 올바른 구문이 무엇인지 궁금해하는 이 페이지의 다른 사람들을 위해 다음을 참조하세요.

.h 파일에서...

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

그리고 .cpp 파일에서

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;

이 코드는 잘 구성되어 있습니다.인스턴스화 시점에 템플릿 정의가 표시된다는 점만 주의하면 됩니다.표준 § 14.7.2.4를 인용하면 다음과 같습니다.

내보내지 않은 함수 템플릿, 내보내지 않은 멤버 함수 템플릿, 내보내지 않은 멤버 함수 또는 클래스 템플릿의 정적 데이터 멤버의 정의는 명시적으로 인스턴스화되는 모든 번역 단위에 있어야 합니다.

이는 템플릿이 지원되는 모든 곳에서 잘 작동합니다.명시적 템플릿 인스턴스화는 C++ 표준의 일부입니다.

귀하의 예는 정확하지만 이식성이 좋지 않습니다.@namespace-sid에서 지적한 대로 사용할 수 있는 약간 더 깔끔한 구문도 있습니다.

템플릿 클래스가 공유될 일부 라이브러리의 일부라고 가정합니다.템플릿 클래스의 다른 버전을 컴파일해야 합니까?라이브러리 관리자는 클래스의 가능한 모든 템플릿 사용을 예상해야 합니까?

대체 접근 방식은 현재 가지고 있는 것에 약간의 변형을 가하는 것입니다.템플릿 구현/인스턴스화 파일인 세 번째 파일을 추가합니다.

foo.h 파일

// Standard header file guards omitted

template <typename T>
class foo
{
public:
    void bar(const T& t);
};

foo.cpp 파일

// Always include your headers
#include "foo.h"

template <typename T>
void foo::bar(const T& t)
{
    // Do something with t
}

foo-impl.cpp 파일

// Yes, we include the .cpp file
#include "foo.cpp"
template class foo<int>;

한 가지 주의할 점은 컴파일러에게 컴파일하라고 지시해야 한다는 것입니다. foo-impl.cpp 대신에 foo.cpp 후자를 컴파일하면 아무 일도 일어나지 않습니다.

물론 세 번째 파일에 여러 구현이 있거나 사용하려는 각 유형에 대해 여러 구현 파일이 있을 수 있습니다.

이는 다른 용도로 템플릿 클래스를 공유할 때 훨씬 더 많은 유연성을 제공합니다.

또한 이 설정은 각 번역 단위에서 동일한 헤더 파일을 다시 컴파일하지 않기 때문에 재사용된 클래스의 컴파일 시간을 줄여줍니다.

이것은 분명히 불쾌한 해킹은 아니지만, 주어진 템플릿과 함께 사용하려는 모든 클래스/유형에 대해 이를 수행해야 한다는 사실(명시적인 템플릿 특수화)을 알고 있어야 합니다.템플릿 인스턴스화를 요청하는 많은 유형의 경우 .cpp 파일에 많은 줄이 있을 수 있습니다.이 문제를 해결하려면 사용하는 모든 프로젝트에 TemplateClassInst.cpp를 두어 인스턴스화할 유형을 더 효과적으로 제어할 수 있습니다.분명히 이 솔루션은 ODR을 깨뜨릴 수 있으므로 완벽하지는 않습니다.

최신 표준에는 키워드(export) 이 문제를 완화하는 데 도움이 되지만 내가 아는 컴파일러에서는 Comeau 외에는 구현되지 않습니다.

참조 FAQ 라이트 이것에 관해서.

응, 그게 표준적인 방법이야 전문화 명시적인 인스턴스화.언급한 대로 이 템플릿을 다른 유형으로 인스턴스화할 수 없습니다.

편집하다:댓글을 토대로 수정했습니다.

이는 템플릿 함수를 정의하는 표준 방법입니다.제가 읽은 템플릿 정의 방법은 세 가지가 있는 것 같습니다.아니면 아마도 4.각각 장단점이 있습니다.

  1. 클래스 정의에서 정의하세요.나는 클래스 정의가 엄격하게 참조용이고 읽기 쉬워야 한다고 생각하기 때문에 이것을 전혀 좋아하지 않습니다.그러나 외부보다 클래스에서 템플릿을 정의하는 것이 훨씬 덜 까다롭습니다.그리고 모든 템플릿 선언이 동일한 수준의 복잡성을 갖는 것은 아닙니다.이 방법은 또한 템플릿을 실제 템플릿으로 만듭니다.

  2. 동일한 헤더에 있지만 클래스 외부에 템플릿을 정의합니다.이것은 내가 가장 선호하는 방식이다.클래스 정의를 깔끔하게 유지하고 템플릿은 실제 템플릿으로 유지됩니다.그러나 까다로울 수 있는 전체 템플릿 이름이 필요합니다.또한 귀하의 코드는 모든 사람이 사용할 수 있습니다.그러나 코드를 인라인으로 만들어야 하는 경우 이것이 유일한 방법입니다.클래스 정의 끝에 .INL 파일을 만들어 이를 수행할 수도 있습니다.

  3. header.h 및implementation.CPP를 main.CPP에 포함합니다.제 생각에는 그렇게 된 것 같아요.사전 인스턴스화를 준비할 필요가 없으며 실제 템플릿처럼 작동합니다.내가 가진 문제는 그것이 자연스럽지 않다는 것입니다.우리는 일반적으로 소스 파일을 포함하지 않으며 포함할 것으로 예상하지 않습니다.소스 파일을 포함시켰기 때문에 템플릿 함수를 인라인할 수 있을 것 같습니다.

  4. 게시된 마지막 방법은 3번과 마찬가지로 소스 파일에서 템플릿을 정의하는 것입니다.그러나 소스 파일을 포함하는 대신 템플릿을 필요한 템플릿으로 미리 인스턴스화합니다.이 방법에는 아무런 문제가 없으며 때로는 유용합니다.우리는 하나의 큰 코드를 갖고 있는데, 인라인 처리의 이점을 누릴 수 없으므로 CPP 파일에 넣기만 하면 됩니다.그리고 일반적인 인스턴스화를 알고 있다면 이를 미리 정의할 수 있습니다.이렇게 하면 기본적으로 동일한 내용을 5, 10번 작성하지 않아도 됩니다.이 방법은 코드를 독점적으로 유지하는 이점이 있습니다.하지만 CPP 파일에 정기적으로 사용되는 작은 기능을 넣는 것은 권장하지 않습니다.이는 라이브러리의 성능을 저하시킵니다.

참고로, 저는 obj 파일이 부풀어 오르면 어떤 결과가 나올지 알지 못합니다.

당신이 제시한 예에는 아무런 문제가 없습니다.하지만 함수 정의를 cpp 파일에 저장하는 것은 효율적이지 않다고 생각합니다.나는 함수의 선언과 정의를 분리해야 한다는 점만 이해합니다.

BCCL(Boost Concept Check Library)을 명시적 클래스 인스턴스화와 함께 사용하면 cpp 파일에서 템플릿 함수 코드를 생성하는 데 도움이 될 수 있습니다.

업데이트할 시간입니다!인라인(.inl 또는 기타) 파일을 만들고 그 안에 모든 정의를 복사하기만 하면 됩니다.각 기능 위에 템플릿을 추가해야 합니다(template <typename T, ...>).이제 인라인 파일에 헤더 파일을 포함하는 대신 반대 작업을 수행합니다.인라인 파일 포함 ~ 후에 수업 선언 (#include "file.inl").

왜 아무도 이것을 언급하지 않았는지 모르겠습니다.즉각적인 단점은 없습니다.

한 가지 예를 들어 보겠습니다. 어떤 이유로 템플릿 클래스를 갖고 싶다고 가정해 보겠습니다.

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

Visual Studio를 사용하여 이 코드를 컴파일하면 즉시 작동합니다.gcc는 링커 오류를 생성합니다(여러 .cpp 파일에서 동일한 헤더 파일을 사용하는 경우).

error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here

구현을 .cpp 파일로 이동할 수 있지만 다음과 같이 클래스를 선언해야 합니다.

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test();

template <>
void DemoT<bool>::test();

// Instantiate parametrized template classes, implementation resides on .cpp side.
template class DemoT<bool>;
template class DemoT<int>;

그러면 .cpp는 다음과 같습니다.

//test_template.cpp:
#include "test_template.h"

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

헤더 파일에 마지막 두 줄이 없으면 gcc는 제대로 작동하지만 Visual Studio에서는 오류가 발생합니다.

 error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test@?$DemoT@H@@QEAAXXZ) referenced in function

.dll 내보내기를 통해 함수를 노출하려는 경우 템플릿 클래스 구문은 선택 사항이지만 이는 Windows 플랫폼에만 적용 가능하므로 test_template.h는 다음과 같습니다.

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

#ifdef _WIN32
    #define DLL_EXPORT __declspec(dllexport) 
#else
    #define DLL_EXPORT
#endif

template <>
void DLL_EXPORT DemoT<int>::test();

template <>
void DLL_EXPORT DemoT<bool>::test();

이전 예제의 .cpp 파일을 사용합니다.

그러나 이는 링커에 더 많은 골칫거리를 주므로 .dll 함수를 내보내지 않는 경우 이전 예제를 사용하는 것이 좋습니다.

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