2016-09-05 1 views
2

[OK]を、私はこの問題についてこことそこに多くの答えを読んだが、おそらく私は正しい構文を知らないので、これを行う方法を理解することはできません。テンプレート以外のクラスの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); 

は今、私は別のアプローチを試みたが、すべての機能以来、私は見つけることができませんでし一度に一つの過負荷を自動的にテンプレートを実装していないだけの例を見てこの作品を作る方法。

もちろん、これはC++であり、QTが追加されています。

+3

あなたが探しているような言葉は、*特化*で、過負荷ではありません。 * C++テンプレートのスペシャリゼーション*を検索してください。 –

+0

テンプレートは、各タイプのコードが同じ場合に便利です。あなたの関数がデータ構造に応じて異なる場合は、スマート関数のオーバーロードが最適な解決策です。 –

+1

1つの中の何かを変更することで、すべてを変更するようなことが集中している場合、extern関数を呼び出すのはどうですか?静的QByteArray Serialize(int value){return extern_serialize (value);}おそらく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を生成できます。私は「テンプレート」動作を実装しなければならないとしたら


は、これが最初の解決策になる(ただスクラッチ!):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の配列)を直列化する通常のメモリバッファを作成し、オーバーロードされた関数はその配列を適切な入力データ構造にのみ適合させる必要があります。

このようにして、クラスロジック(たとえば、データメンバー)が変更されたときは、ヘルパー関数のみを変更する必要があります。

関連する問題