我想制作一个模板类的
__attribute__((packed))
版本,以在打包结构中使用它来以字节形式发送或接收。但我不希望打包的成本影响该类的常规使用的算术和其他方面(使用带有 c++14 的 GCC 为 ARM 进行编译)。
所以我有一个像这个例子一样的模板类:
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>
作为参数的函数都可能需要重载。
至于其他选项:
Vec3
类无法从 Vec3
派生,因为常规 Vec3
未打包(我的 GCC 版本不会在该类上引发错误,即使它可能是未定义的行为)。template<typename T, bool Packed> struct Vec3 {}
以及打包和非打包的专业化并不能解决必须复制所有内容的问题。v.unpack()
(如果你忘记了,就会在编译器输出中哭泣)要明确的是,我想要的是一种自动将打包类转换为常规类的方法,就像 C 数组衰减为指针一样。
@463035818_is_not_an_ai 评论中建议的答案可以解决问题。
#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
,但我的类有更多模板类型参数,因此我的实现会变得更长一些。