在 C++14 中创建模板类的打包版本

问题描述 投票:0回答:1

我想制作一个模板类的

__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 数组衰减为指针一样。

c++ templates c++14 packed
1个回答
0
投票

@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
,但我的类有更多模板类型参数,因此我的实现会变得更长一些。

© www.soinside.com 2019 - 2024. All rights reserved.