繁体   English   中英

非模板类中没有T参数的模板

[英]Templates without T parameters in a non-template class

好的,关于这个问题,我到处都读到了很多答案,但是可能由于我不知道正确的语法,所以我不知道该怎么做。

我有一个非模板类,该类必须实现不同的静态实用程序功能,主要用于序列化和反序列化。 我目前拥有的是这样的:

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 ++。

如评论中所述,它称为模板专门化,如下所示:

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时需要添加template参数。

IMO强制使用模板专业化来解决您的问题,这可能是一个糟糕的选择。

正如我在评论中已经说过的,当每种数据类型的代码结构都相等时,模板通常是好的。

序列化是一个微妙的操作(广播,原始内存等),数据结构可以定义不同的隐式转换并产生UB。


如果我必须实现“模板”行为,那么这将是第一个解决方案(只是从头开始!):

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];
    }
  }
}; 

其中out_iterator必须是output_iterator ,而::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数组),然后重载函数应仅在适当的输入数据结构中适应该数组。

这样,当类逻辑(例如,数据成员)更改时,您应该仅修改帮助程序功能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM