好的,我在这里和那里读到了很多关于这个问题的答案,但可能因为我不知道正确的语法,我无法弄清楚如何做到这一点。
我有一个非模板类,它必须实现不同的静态实用程序函数,主要用于序列化和反序列化。我现在拥有的是这样的:
blob.UploadFromStream(stream);
现在,我更喜欢将所有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
现在,我尝试了不同的方法,但由于我看到的所有功能都只是自动实现模板的示例而不是一次过载,我无法找到如何使其工作。
当然这是C ++,增加了QT。
答案 0 :(得分: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
时需要添加模板参数。
答案 1 :(得分:0)
IMO强制使用模板专业化的解决方案可能是一个糟糕的选择设计。
正如我在评论中已经说过的,当每种数据类型的代码结构相同时,模板通常都很好。
序列化是一种微妙的操作(转换,原始内存等),数据结构可以定义不同的隐式转换并产生UB。
如果我必须实现一个“模板”行为,这将是第一个解决方案(只是一个划痕!):
function log() {
console.log(new Error().stack);
}
function foo() {
log();
}
function bar() {
foo();
}
bar();
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];
}
}
};
必须是output_iterator
,而out_iterator
必须是::value_type
的隐式可转换类型。
可以使用不同的数据结构(容器)调用该函数:
unsigned char
然而,正如我已经说过的那样,我永远不会采用这种解决方案。相反,我将为各种类型使用简单的函数重载。
为了避免多次写同一个东西,我将定义一个包含该类逻辑的唯一辅助函数(私有方法)。
例如,辅助函数可以创建一个普通的内存缓冲区,在其中序列化类(char数组),然后重载函数应该只在适当的输入数据结构中调整该数组。
这样,当类逻辑(例如,数据成员)发生变化时,您应该只修改辅助函数。