2016-09-05 2 views
2

좋아,이 문제에 대해 많은 답변을 읽었지만 적절한 구문을 모르기 때문에 아마도이 작업을 수행 할 방법을 알 수 없습니다.템플릿이 아닌 클래스에서 T 매개 변수가없는 템플릿

필자는 직렬화와 비 직렬화를 위해 주로 다른 정적 유틸리티 함수를 구현해야하는 템플릿이 아닌 클래스가 있습니다.

class Data_Base : public QObject 
{ 
    ... 
protected: 
    static QByteArray Serialize(int value); 
    static int DeserializeInt(QByteArray ser); 
    static QByteArray Serialize(char *value); 
    static char *DeserializeCharArr(QByteArray ser); 
    static QByteArray Serialize(QString value); 
    static QString DeserializeQString(QByteArray ser); 
    .... 
} 

지금, 그것은 좋을 것이기 때문에, 템플릿으로 모든 Deserialize* 기능을 선호하는 것 : 내가 현재 가지고하면이 같은 것입니다. 또한 보너스로 Serialize 함수를 템플릿으로 사용하므로 실제로 호출 할 오버로드를 명시 적으로 명시해야합니다. 이 방법을 사용할 수 있습니다 뭔가 : 이제

QByteArray ba = Serialize<int>(5); 
... 
int theValue = Deserialize<int>(ba); 

, 나는 다른 접근을 시도했지만, 모든 기능 때문에 내가 알 수없는 시간에 자동으로가 아니라 하나의 과부하를 템플릿을 구현 단지 예를 보았다 이 작품을 만드는 방법.

물론 이것은 QT가 추가 된 C++입니다. 코멘트에 명시된 바와 같이

+3

당신이 찾고있는 것 같은 용어는 * 전문화 *이며 과부하가 아닙니다. * C++ 템플릿 전문화 *에 대한 검색을 수행하십시오. –

+0

템플릿은 각 유형에 대해 코드가 동일 할 때 유용합니다. 함수가 데이터 구조에 따라 다르면 똑똑한 함수 오버로드가 가장 좋은 솔루션입니다. –

+1

하나의 요소를 변경하면 모든 요소가 변경되므로 함수를 호출하는 방법은 어떻습니까? static QByteArray (extern_serialize (value);} 모두 직렬화 (int 값);} 아마도 extern 함수를 친구로 만드는 것과 결합되었을 것입니다. – Aziuth

답변

0

는,이 같은 템플릿 특수화 전화를 보이는됩니다 :

class X 
{ 
    public: 
    template<typename T> 
    static QByteArray Serialize(T const& t); 

    template<typename T> 
    static T Deserialize(QByteArray& v); 
}; 

template<> 
QByteArray X::Serialize(int const& t) 
{ 
    /* ... */ 
} 

template<> 
QByteArray X::Serialize(QString const& t) 
{ 
    /* ... */ 
} 

template<> 
int X::Deserialize(QByteArray& v) 
{ 
    /* ... */ 
} 

template<> 
QString X::Deserialize(QByteArray& v) 
{ 
    /* ... */ 
} 

QByteArray x=X::Serialize(5); 
int y=X::Deserialize<int>(x); 

당신이 인수의 유형에서 추론 할 수 있기 때문에 템플릿 매개 변수를 지정할 필요가 없습니다 Serialize를 사용하여.

그러나 반환 유형으로 추론 할 수 없으므로 Deserialize을 사용할 때 템플릿 매개 변수를 추가해야합니다.

+0

감사합니다. 게시하기 전에 이미이 솔루션을 사용해 보았습니다. 그러나 클래스 내부에이 코드를 작성하려고하면 컴파일러에서 'error : 비 - 네임 스페이스의 명시 적 특수화'라고 말합니다. 이것은 클래스 정의에 템플릿 함수를 작성할 수 없다는 것을 의미합니까? – frarugi87

+0

@ frarugi87 수업을 사용하여 답변을 편집했습니다. 아마도 전문화를 클래스 정의에 넣을 수 있습니다. 클래스 정의는 프로토 타입의 선언 만 포함합니다. – TFM

+0

이것이 작동하는 것 같습니다. 선언과 헤더와 소스 파일의 정의를 나눌 때 할 수있는 유일한 일은 헤더 파일의 끝 부분에있는'template <> QByteArray X :: Serialize (int value);'(등등)를 헤더 파일의 끝에 추가하는 것입니다. 클래스 정의. 고맙습니다! – frarugi87

0

IMO는 템플릿 전문화를 사용하여 솔루션을 선택하는 것이 좋지 않을 수 있습니다.

이미 주석에서 말했듯이 템플릿은 코드 구조가 각 데이터 유형과 동일 할 때 일반적으로 좋습니다.

직렬화는 복잡한 작업 (캐스팅, 원시 메모리 등)이며 데이터 구조는 서로 다른 암시 적 변환을 정의하고 UB를 생성 할 수 있습니다. 내가하는 A "템플릿" 동작을 구현해야한다면


, 이것은 최초의 솔루션이 될 것입니다 (다만 스크래치!) 다음 out_iterator해야이 output_iterator

struct Foo { 
    // Some data member variables. 
    std::string m_nopod; 

    // Serialize data object. 'It' must to be a output iterator 
    template<typename It> 
    void serialize(It out_iterator) { 
    constexpr size_t BYTES_FOR_SIZE = sizeof(decltype(m_nopod.size())); 
    constexpr size_t BYTES_FOR_CHAR = sizeof(decltype(m_nopod)::value_type); 

    // size definitions. 
    const auto len_str = m_nopod.size(); 
    const auto len_data = BYTES_FOR_CHAR * len_str; 

    // Temporary memory buffers. 
    uint8_t memory_size[BYTES_FOR_SIZE]; 
    auto memory_data = std::make_unique<uint8_t[]>(len_data); 

    // Raw bytes copy. 
    std::memcpy(memory_size, &len_str, BYTES_FOR_SIZE); 
    std::memcpy(memory_data.get(), m_nopod.data(), len_data); 

    // write with the iterator. 
    for (size_t i = 0; i < BYTES_FOR_SIZE; ++i) { 
     *out_iterator = memory_size[i]; 
    } 

    for (size_t i = 0; i < len_data; ++i) { 
     *out_iterator = memory_data[i]; 
    } 
    } 
}; 

, ::value_type은 암시 적 변환 유형이 unsigned char이어야합니다.

기능

는 서로 다른 데이터 구조 (용기)로 호출 할 수 있습니다 : 이미 말했듯

int main(int argc, char *argv[]) { 
    std::vector<char> memory_buffer_char; 
    std::vector<int> memory_buffer_int; 
    std::string memory_buffer_str; 

    Foo foo{"a_string"}; 

    foo.serialize(std::back_inserter(memory_buffer_char)); 
    foo.serialize(std::back_inserter(memory_buffer_int)); 
    foo.serialize(std::back_inserter(memory_buffer_str)); 
    return 0; 
} 

은, 그러나, 나는 그 솔루션을 채택하지 않을 것이다. 오히려 다양한 유형의 함수에 간단한 오버로딩을 사용할 것입니다.

동일한 것을 두 번 이상 쓰지 않으려면 클래스의 논리를 포함하는 고유 한 도우미 함수 (개인 메서드)를 정의합니다.

예를 들어 도우 퍼 함수는 클래스 (char 배열)를 직렬화하는 일반 메모리 버퍼를 만들 수 있으며 오버로드 된 함수는 해당 입력 데이터 구조에서만 해당 배열을 적용해야합니다.

그런 식으로 클래스 논리 (예 : 데이터 멤버)가 변경되면 헬퍼 함수 만 수정해야합니다.

관련 문제