【发布时间】:2017-04-30 21:36:17
【问题描述】:
我正在设计一个实用程序标头,可以将二进制数据从sf::InputStream 中抽取出来。为了便于使用,它包含一个函数名称readFromStream,它有很多(模板化和非模板化)重载,用于自动反序列化标准布局类型和类型复合,如向量、元组和我定制设计的@987654327 @ 班级。完整的实现可以在这里找到:https://github.com/JoaoBaptMG/ReboundTheGame/blob/master/MainGame/utility/streamCommons.hpp
所以,我定义了一个重载readFromStream,它通过再次递归调用readFromStream 抽出任何类型的向量:
template <typename T, typename std::enable_if<!is_optimization_viable<T>::value, int>::type = 0>
bool readFromStream(sf::InputStream &stream, std::vector<T> &value)
{
size_t size;
if (!readFromStream(stream, VarLength(size)))
return false;
std::vector<T> newVal(size, T());
for (auto &val : newVal)
if (!readFromStream(stream, val))
return false;
newVal.swap(value);
return true;
}
我想为标准布局类编写一个优化版本因为readFromStream 没有重载,所以我们可以利用它们的内存布局并将它们放在一个单一的read电话:
// trait is_optimization_viable is what I'm having trouble to write
template <typename T, typename std::enable_if<is_optimization_viable<T>::value, int>::type = 0>
bool readFromStream(sf::InputStream &stream, std::vector<T> &value)
{
size_t size;
if (!readFromStream(stream, VarLength(size)))
return false;
std::vector<T> newVal(size, T());
if (stream.read(newVal.data(), size*sizeof(T)) != size*sizeof(T))
return false;
newVal.swap(value);
return true;
}
好吧,我可以使用其他答案中描述的解决方案来检测功能的存在,但有一个问题。当类型是标准布局时,我有一个默认的readFromStream,如下所示:
template <typename T, typename std::enable_if<std::is_standard_layout<T>::value, int>::type = 0>
bool readFromStream(sf::InputStream &stream, T& value)
{
return stream.read((void*)&value, sizeof(T)) == sizeof(T);
}
所以,总是有一个函数来进行序列化,而不仅仅是我想要的那个。我想在这里解决的问题是:如何检测到类型 T 的非默认 readFromString 的存在,以禁用 readFromString 的优化版本 std::vector<T>?
我尝试了一些技巧。我无法将优化限制为 POD 类型,因为我在某些要反序列化的类型上使用了 sf::Vector2<T>,这不是 POD。我尝试比较使用非模板化和模板化函数时得到的函数地址,例如:
using FPtr = bool(*)(sf::InputStream&, T&);
return (FPtr)readFromStream == (FPtr)readFromStream<T>;
但是,奇怪的是,它不起作用。我研究了很多解决方案,但没有一个能适应我的需要。也许这在 C++ 中是不可能的,我将不得不求助于“标记”我不想优化的类型。或者,也许这是我没有想到的一些晦涩的模板。我怎么能这样做?
【问题讨论】:
-
首先你需要一些补充的
std::enable_if子句,因为std::is_standard_layout<T>可能不是is_optimization_viable<T>的反义词,而且你手头有歧义。 -
@HenriMenke 是的,这不是相反的;实际上,后一种特征需要前者才能满足我的需要。我可能没有正确描述我想要什么。
-
为什么要“禁用 readFromString 的优化版本”?如果要检查是否存在异常序列化函数,则检测代码与检查是否存在常规序列化函数的检测代码基本相同,只是调整了签名。
-
@VTT 有一些标准布局函数(如
std::string、我自己的GameObjectDescriptor以及基本上所有带有指针的函数)不应该被快速反序列化位图;所以我想检查是否存在特定的重载,以便使用它更安全。
标签: c++ templates c++14 template-meta-programming sfinae