programing tip

템플릿 클래스의 단일 메서드에 대한 템플릿 전문화

itbloger 2020. 10. 6. 07:58
반응형

템플릿 클래스의 단일 메서드에 대한 템플릿 전문화


템플릿 클래스를 포함하는 다음 헤더가 적어도 두 개의 .CPP파일에 포함되어 있다는 점을 항상 고려하면 이 코드는 올바르게 컴파일됩니다.

template <class T>
class TClass 
{
public:
  void doSomething(std::vector<T> * v);
};

template <class T>
void TClass<T>::doSomething(std::vector<T> * v) {
  // Do something with a vector of a generic T
}

template <>
inline void TClass<int>::doSomething(std::vector<int> * v) {
  // Do something with a vector of int's
}

그러나 전문화 방법의 인라인에 유의하십시오. 메서드가 두 번 이상 정의되므로 링커 오류 (VS2008에서는 LNK2005)를 피해야합니다. AFAIK 전체 템플릿 전문화는 간단한 메서드 정의와 동일하기 때문에 이것을 이해합니다.

그래서 어떻게 제거 inline합니까? 코드를 사용할 때마다 중복되어서는 안됩니다. 나는 Google을 검색하고 여기에서 몇 가지 질문을 읽고 많은 제안 된 솔루션을 시도했지만 성공적으로 구축되지 않았습니다 (적어도 VS 2008에서는).

감사!


간단한 함수와 마찬가지로 선언 및 구현을 사용할 수 있습니다. 헤더 선언을 넣으십시오.

template <>
void TClass<int>::doSomething(std::vector<int> * v);

cpp 파일 중 하나에 구현을 넣으십시오.

template <>
void TClass<int>::doSomething(std::vector<int> * v) {
 // Do somtehing with a vector of int's
}

인라인을 제거하는 것을 잊지 마십시오 (이 솔루션이 작동하지 않을 것이라고 생각했습니다 :)). VC ++ 2005에서 확인


전문화 정의를 CPP 파일로 이동해야합니다. 함수를 템플릿으로 선언하지 않아도 템플릿 클래스의 멤버 함수 특화가 가능합니다.


키워드를 인라인으로 제거 할 이유가 없습니다.
어쨌든 코드의 의미는 변경되지 않습니다.


어떤 이유로 든 인라인을 제거하려면 maxim1000의 솔루션이 완벽하게 유효합니다.

그러나 귀하의 의견에서 inline 키워드는 모든 내용이 포함 된 함수가 항상 인라인되지만 실제로 컴파일러 최적화에 크게 의존하는 AFAIK를 의미한다고 생각하는 것 같습니다.

C ++ FAQ 에서 인용

함수를 인라인으로 지정하는 방법에는 여러 가지가 있습니다. 그 중 일부는 인라인 키워드를 포함하고 다른 일부는 포함하지 않습니다. 함수를 인라인으로 지정하는 방법에 관계없이 컴파일러가 무시하도록 허용하는 요청입니다. 컴파일러는 인라인으로 지정된 함수를 호출하는 위치의 일부, 전부를 인라인 확장하거나 전혀 확장하지 않을 수 있습니다. (절망적으로 모호해 보이더라도 낙심하지 마십시오. 위의 유연성은 실제로 큰 이점입니다. 컴파일러가 큰 함수를 작은 함수와 다르게 처리 할 수있게 해주 며, 선택하면 디버그하기 쉬운 코드를 컴파일러가 생성 할 수 있습니다. 올바른 컴파일러 옵션.)

따라서 해당 함수가 실제로 실행 파일을 부 풀릴 것이라는 것을 알지 못하거나 다른 이유로 템플릿 정의 헤더에서 제거하려는 경우가 아니면 실제로 해를 끼치 지 않고 그대로 둘 수 있습니다.


이것은 약간의 OT이지만 다른 사람을 도울 경우를 대비하여 여기에 남겨 둘 것이라고 생각했습니다. 나는 나를 여기로 이끈 템플릿 전문화에 대해 인터넷 검색을하고 있었고 @ maxim1000의 대답은 정확하고 궁극적으로 내 문제를 파악하는 데 도움이되었지만 충분히 명확하다고 생각하지 않았습니다.

내 상황은 OP와 약간 다릅니다 (그러나이 대답을 떠날만큼 충분히 유사합니다). 기본적으로 "상태 유형"을 정의하는 모든 종류의 클래스와 함께 타사 라이브러리를 사용하고 있습니다. 이러한 유형의 핵심은 단순히 enums이지만 클래스는 모두 공통 (추상) 부모에서 상속되며 연산자 오버로딩 및 함수와 같은 다른 유틸리티 함수를 제공 static toString(enum type)합니다. 각 상태 enum는 서로 다르며 관련이 없습니다. 예를 들어, 하나 enum에는 필드가 NORMAL, DEGRADED, INOPERABLE있고 다른 하나 에는 AVAILBLE, PENDING, MISSING등이 있습니다. 내 소프트웨어는 다양한 구성 요소에 대한 다양한 유형의 상태를 관리합니다. toString기능 을 활용하고 싶었다는 생각이 들었습니다.enum클래스이지만 추상적이기 때문에 직접 인스턴스화 할 수 없었습니다. 사용하고 싶은 각 수업을 확장 할 수 있었지만 궁극적으로 내가 신경 쓰는 구체적인 상태가 되는 template수업 을 만들기로 결정했습니다 . 아마도 그 결정에 대해 약간의 논쟁이있을 수 있지만, 각 추상 클래스를 나만의 커스텀 클래스로 확장 하고 추상 함수를 구현하는 것보다 훨씬 적은 작업이라고 느꼈습니다 . 물론 내 코드에서 .NET의 문자열 표현 을 호출 하고 인쇄 할 수 있기를 원 했습니다 . 모든 s는 전혀 관련이 없었기 때문에 각각 고유 한typenameenumenum.toString(enum type)enumenumtoString(내가 배운 몇 가지 연구 후) 템플릿 전문화를 사용하여 호출해야하는 함수. 그것은 나를 여기로 이끌었습니다. 다음은이 작업을 올바르게 수행하기 위해 수행해야하는 MCVE입니다. 그리고 실제로 내 솔루션은 @ maxim1000과 약간 다릅니다.

이것은 s에 대한 (매우 단순화 된) 헤더 파일입니다 enum. 실제로 각 enum클래스는 자체 파일에 정의되어 있습니다. 이 파일은 내가 사용중인 라이브러리의 일부로 제공되는 헤더 파일을 나타냅니다.

// file enums.h
#include <string>

class Enum1
{
public:
  enum EnumerationItem
  {
    BEARS1,
    BEARS2,
    BEARS3
  };

  static std::string toString(EnumerationItem e)
  {
    // code for converting e to its string representation,
    // omitted for brevity
  }
};

class Enum2
{
public:
  enum EnumerationItem
  {
    TIGERS1,
    TIGERS2,
    TIGERS3
  };

  static std::string toString(EnumerationItem e)
  {
    // code for converting e to its string representation,
    // omitted for brevity
  }
};

다음 파일을 다른 코드 블록으로 분리하기 위해이 줄을 추가합니다.

// file TemplateExample.h
#include <string>

template <typename T>
class TemplateExample
{
public:
  TemplateExample(T t);
  virtual ~TemplateExample();

  // this is the function I was most concerned about. Unlike @maxim1000's
  // answer where (s)he declared it outside the class with full template
  // parameters, I was able to keep mine declared in the class just like
  // this
  std::string toString();

private:
  T type_;
};

template <typename T>
TemplateExample<T>::TemplateExample(T t)
  : type_(t)
{

}

template <typename T>
TemplateExample<T>::~TemplateExample()
{

}

다음 파일

// file TemplateExample.cpp
#include <string>

#include "enums.h"
#include "TemplateExample.h"

// for each enum type, I specify a different toString method, and the
// correct one gets called when I call it on that type.
template <>
std::string TemplateExample<Enum1::EnumerationItem>::toString()
{
  return Enum1::toString(type_);
}

template <>
std::string TemplateExample<Enum2::EnumerationItem>::toString()
{
  return Enum2::toString(type_);
}

다음 파일

// and finally, main.cpp
#include <iostream>
#include "TemplateExample.h"
#include "enums.h"

int main()
{
  TemplateExample<Enum1::EnumerationItem> t1(Enum1::EnumerationItem::BEARS1);
  TemplateExample<Enum2::EnumerationItem> t2(Enum2::EnumerationItem::TIGERS3);

  std::cout << t1.toString() << std::endl;
  std::cout << t2.toString() << std::endl;

  return 0;
}

그리고 이것은 다음을 출력합니다.

BEARS1
TIGERS3

No clue if this is the ideal solution to solve my problem, but it worked for me. Now, no matter how many enumeration types I end up using, all I have to do is add a few lines for the toString method in the .cpp file, and I can use the libraries already-defined toString method without implementing it myself and without extending each enum class I want to use.

참고URL : https://stackoverflow.com/questions/1723537/template-specialization-of-a-single-method-from-a-templated-class

반응형