带有元组的C++可变模板
C++ variadic templates with tuples
我想写一个函数,从二进制缓冲区中提取一些数据(假设数据是按顺序存储的(。该函数在提取的数据之后返回数据和指针,如
std::tuple<const unsigned char *, int, double, float> data = Extract<int, double, float>(p_buffer);
其从p_buffer
中提取int
、double
和float
编号,并且data
的第一个值指示从哪里开始下一个提取工作。
我试着写这样的东西。
#include <tuple>
typedef unsigned char byte;
template<class TFirst, class... TRest>
struct Extractor
{
static std::tuple<const byte *, TFirst, TRest...> Extract(const byte *p_current)
{
TFirst first_value;
TRest... rest_values; // Not working.
std::tie(p_current, first_value) = Extractor<TFirst>::Extract(p_current);
std::tie(p_current, rest_values...) = Extractor<TRest...>::Extract(p_current);
return std::make_tuple(p_current, first_value, rest_values...);
}
};
template<class T>
struct Extractor<T>
{
static std::tuple<const byte *, T> Extract(const byte *p_current)
{
return std::make_tuple(p_current + sizeof(T), *reinterpret_cast<const T *>(p_current));
}
};
它没有编译,因为"参数包不能在此上下文中展开"。我听说函数模板不能部分专门化,所以我使用structs。如何使其发挥作用?
这里有一个纯C++11解决方案:
#include <tuple>
#include <type_traits>
typedef unsigned char byte;
template <class Type>
void ExtractValue(const byte*& p_current, Type& value)
{
value = *reinterpret_cast<const Type*>(p_current);
p_current += sizeof(Type);
}
template <size_t index, class... Types>
typename std::enable_if<index == sizeof...(Types)>::type
ExtractImpl(const byte*& p_current, std::tuple<Types...>& values)
{}
template <size_t index, class... Types>
typename std::enable_if<(index < sizeof...(Types))>::type
ExtractImpl(const byte*& p_current, std::tuple<Types...>& values)
{
ExtractValue(p_current, std::get<index>(values));
ExtractImpl<index + 1>(p_current, values);
}
template <class... Types>
std::tuple<Types...> Extract(const byte *p_current)
{
std::tuple<Types...> values;
ExtractImpl<0>(p_current, values);
return values;
}
这个解决方案不会将p_current
添加到返回的元组中,但您可以很容易地修复它。
我发现这样做要简单得多,根本没有模板递归(示例(:
template<typename T>
T extract(const byte *&p_current)
{
const byte *p = p_current;
p_current += sizeof(T);
return *reinterpret_cast<const T*>(p);
}
template<typename... T>
std::tuple<T...> Extract(const byte *&p_current)
{
return std::tuple<T...>{extract<T>(p_current)...};
}
不幸的是,由于一个持久的错误,gcc以相反的顺序(从右到左(评估tuple
的列表初始化的参数,所以您将在实际示例中看到,它只在clang中正确工作。但是,如果在调用Extract
之前翻转参数列表T...
(仅针对gcc(,仍然可以应用此解决方案。我更喜欢保持简单,等到bug被修复。
TRest... rest_values; // Not working.
这是无效的,不能声明类型为TRest...
的变量,因为它不是一个类型(它是一组类型(。
Yakk上面的评论是一个更干净的解决方案,但如果你真的只想使用元组,你可以这样做:
std::tuple<TRest...> rest_values;
然后修改以下代码以使用它。
您不能简单地将std::tie
与元组元素一起使用(您需要C++14的apply()
函数(,所以我会这样做:
static std::tuple<const byte *, TFirst, TRest...> Extract(const byte *p_current)
{
TFirst first_value;
std::tuple<const char*&, TRest...> rest_values{ p_current, TRest{}... };
std::tie(p_current, first_value) = Extractor<TFirst>::Extract(p_current);
rest_values = Extractor<TRest...>::Extract(p_current);
return std::make_tuple(p_current, first_value, cdr(rest_values));
}
其中cdr()
是Lisp CDR操作,它返回除列表的第一个元素之外的所有内容。
相关文章:
- C++:TypeDef使用元组
- Pybind11:将元组列表从Python传递到C++
- 重载元组索引运算符-C++
- 在C++中,如何通过几种类型从元组中选择多个元素
- 将fold表达式与std::一起用于两个元组
- std::ranges::elements_view,用于自定义类似元组的数据
- 将元组的向量转换/构造为堆
- 专用于 std 元组的模板,而无需用户执行remove_cvref
- 将元组的向量构造成堆
- 元组由 Swig 生成的 Python 包装器返回,用于C++向量
- 将元组类型扩展为可变参数模板?
- 时间复杂度 当具有复合数据类型(如元组或对)时?
- 类内部和外部静态 constexpr 元组之间的差异
- 可变参数模板与使用元组在参数中添加不同的数据对
- 访问和打印元组中的数据,并使用 C++14 使用模板函数显示数据
- boost::包含提升单元的元组的哈希值
- 我正在寻找一种优雅的方式来从元组向量创建tuple_element向量
- 如何在可变参数模板函数中遍历可变参数元组?
- 如何使用 SML 随机生成八进制元组
- 元组的运行时索引