2012-07-04 5 views
1

템플릿 클래스를 만들고 싶고 템플릿 매개 변수의 typeid에 따라 다른 동작을 수행한다면 어떻게 코딩해야합니까?템플릿 클래스의 여러 템플릿 매개 변수에 대해 서로 다른 작업을 수행하려면 어떻게해야합니까?

예를 들어 int 또는 string 여부에 따라 구성원 필드 데이터를 초기화하려는 템플릿 클래스가 있습니다.

#include <string> 

template <class T> 
class A 
{ 
private: 
    T data; 
public: 
    A(); 
}; 

// Implementation of constructor 
template <class T> 
A<T>::A() 
{ 
    if (typeid(T) == typeid(int)) 
    { 
     data = 1; 
    } 
    else if (typeid(T) == typeid(std::string)) 
    { 
     data = "one"; 
    } 
    else 
    { 
     throw runtime_error("Choose type int or string"); 
    } 
} 

이 코드는 다음 주 파일과 함께 컴파일되지 않습니다.

#include "stdafx.h" 
#include "A.h" 
#include <string> 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    A<int> one; 
    return 0; 
} 

오류 : 오류 C2440는 '='실제로 다른-IF 명령문의 int 심지어를 검사 코드 수단 '내부'에 '[2] CONST 문자'로 변환 할 수없는 코드의 해당 부분에 도달 할 수는 없지만

다음 예제에서는 (Perform different methods based on template variable type), 다음 A.h 파일을 시도했지만 A.obj에 A (void)가 이미 정의되어 있다는 링커 오류가 몇 가지 있습니다.

#include <string> 

template <class T> 
class A 
{ 
private: 
    T data; 
public: 
    A(); 
    ~A(); 
}; 

// Implementation of constructor 
template <> 
A<int>::A() 
{ 
    data = 1; 
} 
template <> 
A<std::string>::A() 
{ 
    data = "one"; 
} 

누구든지이 코드를 실행하는 방법을 알고 있습니까? 또한 템플릿 클래스에서 이와 같은 if-else 문을 사용하면 템플릿에서 전원이 제거 될 수 있다는 것을 알고 있습니다. 이 코드를 작성하는 더 좋은 방법이 있습니까?

편집 :

#pragma once 

#include <string> 

// Class definition 
template <class T> 
class A 
{ 
public: 
    A(); 
    ~A(); 
private: 
    T data; 
}; 

// Implementation of initialization 
template < class T > 
struct initial_data 
{ 
    static T data() { throw runtime_error("Choose type int or string"); } 
}; 

template <> 
struct initial_data<int> 
{ 
    static int data() { return 1; } 
}; 

template <> 
struct initial_data<std::string> 
{ 
    static std::string data() { return "one"; } 
}; 

// Definition of constructor 
template <class T> 
A<T>::A() 
    : data(initial_data<T>::data()) 
{ 
} 

다음과 같은 주요 : : 지금 얻을

#include "stdafx.h" 
#include "A.h" 
#include <string> 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    A<int> ione; 

    return 0; 
} 

링커 오류는 다음과 같습니다 스텐 (아래), 지금 다음 아 파일이와 논의 후 테스트 템플릿 4.obj : 오류 LNK2019 : 함수 _wmain에서 참조되는 확인되지 않은 외부 기호 "public : __thiscall A :: ~ A (void)"(?? 1? $ A @ H @@ QAE @ XZ)

+1

1)'_tmain' 쓰레기와 친구들을 사용하지 마십시오. 2) 템플릿과 함께'typeid'를 사용하는 것은 무엇입니까? 'int :: operator = (const char *)'가 없으므로 코드는 단순히'T = int'에 대해 컴파일되지 않습니다 ... 3) 컴파일 에러에 대한 테스트 케이스를 참조하십시오. – Griwes

+1

두 번째 예제로 수행 한 템플릿 전문화는 IMHO로 이동하는 방법입니다. 헤더 파일에 포함 가드를 추가 했습니까? 링커 오류에서 그것은 당신처럼 보이지 않습니다. – Naveen

+0

나는 이것을 위해 SFINAE를 사용할 수 있다고 생각합니다. 'enable_if'와'is_same'을 사용하면 템플릿 params를 기반으로 다른 멤버 함수를 가질 수 있습니다. – jrok

답변

3

명시 적 특수화는 다음과 같습니다. 갈 길.

당신이 A.h를 여러 .cpp에 포함시키고 있다고 가정하고 이것이 문제의 근본 원인입니다.

전문화는 정의이며 A :: A()와 A :: A()의 정의가 하나만 있어야하므로 하나의 .cpp에 있어야합니다.

당신은 통화 당

template <> 
A<int>::A() 
{ 
    data = 1; 
} 
template <> 
A<std::string>::A() 
{ 
    data = "one"; 
} 

에 명시 적 전문성을 이동하고 선언을 계속 그들을 위해 아에

template<> A<int>::A(); 
template<> A<std::string>::A(); 

그래서 컴파일러는 명시 적으로 전문화 알고 있고 아무튼해야합니다 자동으로 추가하려고하지 마십시오.

편집 : g ++ m.cpp f.cpp a.cpp는 이러한 네 가지 파일로 오류를 표시하지 않습니다.

template < class T > 
struct initial_data 
{ 
    static T data() { throw runtime_error("Choose type int or string"); } 
}; 

template <> 
struct initial_data<int> 
{ 
    static int data() { return 1; } 
} 

template <> 
struct initial_data<std::string> 
{ 
    static std::string data() { return "1"; } 
} 

당신이 클래스를 전문으로하는 경우 : 경우

// a.h 
#define A_H 

#include <string> 

template <class T> 
class A 
{ 
private: 
    T data; 
public: 
    A(); 
}; 

template<> A<int>::A(); 
template<> A<std::string>::A(); 

#endif 

// a.cpp 
#include "a.h" 

template <> 
A<int>::A() 
{ 
    data = 1; 
} 
template <> 
A<std::string>::A() 
{ 
    data = "one"; 
} 

// f.cpp 
#include "a.h" 

int f() 
{ 
    A<int> one; 
    A<std::string> two; 
} 

// m.cpp 
#include "a.h" 

int f(); 

int main() 
{ 
    A<int> one; 
    A<std::string> two; 
    f(); 
} 
+0

답변 해 주셔서 감사합니다. 나는 그것이 아직 일하는 것을 얻지 않는다. 선언문을 헤더 파일에 넣지 만 클래스에 넣으시겠습니까? 클래스 내에 배치하면 컴파일러에서 오류 C2931 : 'A ': template-class-id가 'A '의 멤버 함수로 재정의됩니다. 내가 클래스 외부에 배치하면 링커가 말합니다 : 오류 LNK2005 : "public : __thiscall A :: A (int, int)"(?? 0? $ A @ H @@ QAE @ HH @ Z) 이미 정의되었습니다. A.obj – physicalattraction

+0

에서 @physicalattraction에서 전체 예제로 업데이트했습니다. – AProgrammer

+0

그 작품은 분명하고 정확히 내가 뭘 찾고 있어요! :-D – physicalattraction

2

그것은, 내가 다른 구조체에이를 고려하는 것이 좋습니다 것입니다 당신이 T에 따라 동작을 할 단지 c'tor입니다 템플릿 매개 변수에서 다른 전문화 유형은 완전히 다른 유형이며 다른 데이터 및 기능 세트를 가질 수 있습니다.

마지막 :

#include <string> 

template <class T> 
class A 
{ 
private: 
    T data; 
public: 
    A(); 
    ~A(); 
}; 

template <> 
class A <std::string> 
{ 
private: 
    std::string data; 
public: 
    A() { data = "one"; } 
}; 

template <> 
class A <int> 
{ 
private: 
    int data; 
public: 
    A() { data = 1; } 
}; 

:

template <class T> 
A<T>::A() 
    : data(initial_data<T>::data()) 
{ 
} 

종류 스텐

+0

답해 주셔서 감사합니다. 헤더 파일에 위 코드가 있습니다 (구조체 뒤에 세미콜론 포함). 클래스 정의 다음에 배치했습니다. 위의 주와 나는 여전히 링커 오류 LNK 2019를 얻습니다.이 코드가 당신을 위해 작동합니까? 내가 명령 할 권리가 있니? – physicalattraction

+0

@physicalattraction 주문이 잘못되어 있으면 컴파일러가 불평 할 것입니다. LNK2019는 누락 된 외부 기호에 대해 불평하는 링커 오류입니다. 오류 메시지의 정확한 표현을 포함하여 문제를 재현하는 아주 작은 예제를 제공 할 수 있습니다. –

+0

지금 당장 가지고있는 코드로 개 소식을 편집했습니다. 나는 어떤 실수도하지 않는다. 어쩌면 그것을 볼 수 있을까요? – physicalattraction

2

두 번째 솔루션 올바른지에 관하여, 당신이 필요한 것은 템플릿 특수화 (함께 선언과 구현을 유지)입니다 좀 더 세련된 솔루션을 제안한다면 생성자에 매개 변수를 추가하고 템플릿 전문화를 피하십시오.

template <class T> 
class A 
{ 
private: 
    T data; 
public: 
    A(T value) : data(value) {} 
    virtual ~A() {} 
}; 
+0

답변 해 주셔서 감사합니다. 첫 번째 해결책에 대해서 : 어떻게 특수화 된 클래스에서 일반적인 메소드를 호출 할 수 있습니까? 더 구체적으로 : 제네릭 클래스에 GetData() 메서드를 추가하고 main에 입력했습니다 : number(); cout << A.GetData(); 그러면 컴파일러에서 C2039 오류가 발생합니다. 'GetData'는 'A '의 구성원이 아닙니다. 이 문제를 어떻게 해결할 수 있습니까? 두 번째 솔루션에 관해서는 매우 우아합니다. 내 진짜 문제는 조금 더 복잡하지만 필드 데이터는 입력 유형에 따라 메서드를 호출하여 초기화됩니다. 그래서 템플릿 전문화를 사용하려고했습니다. – physicalattraction

+1

클래스와 함께 템플릿을 사용할 때 컴파일러는 각 전문 분야마다 완전히 다른 클래스를 생성합니다. 일반 템플릿 클래스 및 특수 템플릿 클래스는 기본 클래스 및 파생 클래스와 다릅니다. 따라서 두 번째 솔루션을 사용하지 않는 한 각 전문 분야에서 GetData() 메서드를 다시 구현해야합니다. – Sdra