gpt4 book ai didi

c++ - 当模板重载可用时,检查函数的自定义重载是否存在

转载 作者:行者123 更新时间:2023-11-30 05:13:52 25 4
gpt4 key购买 nike

我正在设计一个实用程序 header ,用于从 sf::InputStream 中提取二进制数据.为了便于使用,它包含一个函数名称,readFromStream ,它有很多(模板化和非模板化)重载,用于自动反序列化标准布局类型和类型复合,如 vector 、元组和我的定制设计 grid类(class)。完整的实现可以在这里找到:https://github.com/JoaoBaptMG/ReboundTheGame/blob/master/MainGame/utility/streamCommons.hpp

所以,我定义了一个重载 readFromStream通过调用 readFromStream 抽出任何类型的 vector 再次递归:

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

所以,总有一个函数可以执行序列化,而不仅仅是我想要的那个。我想在这里解决的问题是:如何检测非默认 readFromString 的存在?对于类型 T , 为了禁用 readFromString 的优化版本对于 std::vector<T> ?

我尝试了一些技巧。我不能将优化限制为 POD 类型,因为我使用的是 sf::Vector2<T>在某些我想反序列化的类型上,这不是 POD。我尝试比较使用非模板化函数和模板化函数时获得的函数地址,例如:

using FPtr = bool(*)(sf::InputStream&, T&);
return (FPtr)readFromStream == (FPtr)readFromStream<T>;

但是,奇怪的是,它没有用。我研究了很多解决方案,但没有一个可以适应我的需要。也许这在 C++ 中是不可能的,我将不得不求助于“标记”我不想优化的类型。或者它可能是一些我没想到的晦涩模板。我怎么能这样做?

最佳答案

据我了解,您的问题是:

is_optimization_viable<T>;

可以定义为:

template<typename T>
using is_optimization_viable<T> = std::is_standard_layout<T>;

但事实上,对于 T 的某些值标准布局你仍然需要自定义 bool readFromStream(sf::InputStream &stream, T &value) ,过载,这意味着它们优化可行。

既然您必须编写这些自定义重载,那么您知道那些T 的异常值是。假设它们是类型 X , Y , Z .然后您可以将特征定义为:

#include <type_traits>

template<typename T, typename ...Us>
struct is_one_of;

template<typename T>
struct is_one_of<T> {
static constexpr bool value = false;
};

template<typename T, typename First, typename ...Rest>
struct is_one_of<T,First,Rest...> {
static constexpr bool value =
std::is_same<T,First>::value || is_one_of<T,Rest...>::value;
};

// ^ C++17: `std::disjunction` does the job

template<typename T>
using has_custom_read_from_stream = is_one_of<T,X,Y,Z>;

template<typename T>
struct is_optimization_viable {

static constexpr bool value = std::is_standard_layout<T>::value &&
!has_custom_read_from_stream<T>::value;
};

感谢您宁愿避免持续维护硬编码类型列表 X , Y , Z , 并且更喜欢 SFINAE-probe是否来电readFromStream(s, t)将调用其中一个一些 std::declval -ed 的自定义重载st .

但这只是海市蜃楼。你告诉我们,会有一些过载 readFromStream(s, t)这将编译任何类型的 t .如果是这样,SFINAE 探测器将始终告诉您是的, readFromStream(s, t)将编译 - 对于任何 T作为 t 的不合格类型.你呢仍然必须就是否 T 做出编译时决定是其中之一自定义类型,如果不是,是否是标准布局。

这就是问题所在。判断是否T是其中之一自定义类型,您必须测试它与任何一个的身份如图所示,它们是分离的,或者你必须找到一个独立于它们的特征满足所有且仅自定义类型的身份。如你不要告诉我们那些自定义类型是什么,我不能建议任何这样的特征,但是如果你找到一个,那么将定义或替换has_custom_read_from_stream<T> .

顺便说一句,我支持@NirFriedman 的评论:是std::standard_layout你真的是这个意思吗?

关于c++ - 当模板重载可用时,检查函数的自定义重载是否存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43711573/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com