提问人:azyo 提问时间:9/8/2023 最后编辑:azyo 更新时间:9/11/2023 访问量:52
在 C++ 中创建模板类的打包版本 14
Creating a packed version of a template class in C++14
问:
我想制作一个模板类的版本,在打包的结构中使用它以作为字节发送或接收。但我不希望打包的成本影响算术和其他方面对类的常规使用(使用 GCC 和 c++14 为 ARM 编译)。__attribute__((packed))
所以我有一个模板类,如这个例子:
template<typename T>
struct Vec3 {
T x, y, z;
constexpr Vec3() = default;
constexpr Vec3(T x, T y, T z) : x(x), y(y), z(z) {}
constexpr Vec3& operator=(const Vec3& v);
constexpr Vec3 operator+(const Vec3& v) const;
template<typename U>
constexpr auto operator+(const Vec3<U>& v) const -> Vec3<decltype(T{} + U{})>;
// many other member functions
}
template<typename T, typename U>
constexpr auto dot(const Vec3<T>& v1, const Vec3<U>& v2) -> decltype(T{} * U{});
// other non-member functions
现在我想做一个 Vec3 类的打包版本,如下所示:
#include <type_traits>
template<typename T>
class PackedType;
template<typename T>
using Packed = std::conditional_t<std::is_arithmetic<T>::value, T, PackedType<T>>;
template<typename T>
struct __attribute__((packed)) PackedType<Vec3<T>> {
Packed<T> x, y, z; // make sure the internal type is packable
constexpr PackedType(const Vec3<T>& v) : x(v.x), y(v.y), z(v.z) {}
constexpr operator Vec3<T>() const { return Vec3<T>(T(x), T(y), T(z)); }
}
但这就是它崩溃的地方。对函数的调用期望使用模板参数推导/替换,但不是 ,也不是派生自 。所以编译器无法推断出任何东西。Vec3
PackedType<Vec3<T>>
Vec3
Vec3
我们希望在函数中使用时将打包类转换为常规类。正如我之前所说,我们不希望/不需要对打包的值执行操作,因此制作副本是可以的。Vec3
Vec3
但是现在我们需要为所有函数提供重载以使用类的打包版本,以及所有(常规,打包),(打包,常规),(打包,打包)函数的两个参数等等......我指的不仅仅是 Vec3.h/cpp 文件,任何作为模板化为参数的函数都可能需要重载。Vec3<T>
至于其他选项:
- 打包的类不能派生,因为常规没有打包(我的 GCC 版本不会在该版本上引发错误,即使它可能是未定义的行为)。
Vec3
Vec3
Vec3
- 对包装和非包装进行专业化并不能解决必须复制所有内容的问题。
template<typename T, bool Packed> struct Vec3 {}
- 每次我们需要进行转换时都显式使用 a(如果您忘记了,请在编译器输出时哭泣)
v.unpack()
需要明确的是,我想要的是一种自动将打包类转换为常规类的方法,例如,就像 c 数组衰减为指针一样。
答:
0赞
azyo
9/8/2023
#1
评论中建议的答案可以解决问题。
#include <type_traits>
template<typename T>
struct Vec3 {
using type = T;
T x, y, z;
//...
}
template<typename T>
struct isVec3Conv : std::false_type {};
template<typename T>
struct isVec3Conv<Vec3<T>> : std::true_type {};
template<typename T>
struct isVec3Conv<PackedType<Vec3<T>>> : std::true_type {};
template<typename V1, typename V2,
std::enable_if_t<isVec3Conv<V1>::value && isVec3Conv<V2>::value, bool> = 0>
constexpr auto dot(const V1& v1, const V2& v2) ->
decltype(typename V1::type{} * typename V2::type{});
在这种情况下,我们可以替换为 ,但我的类有更多的模板类型参数,因此我的实现变得更长一些。typename V1::type{}
v1.x
评论
Vec3
Vec3
x
y
z
dot
dot(const T& t, const U& u)
Vec<T>
t
u
Vec<T>