自动转换结构的所有成员

Casting all members of struct automatically

我有一个模板class,其中有很多变量,都是同一类型

template<typename T>
struct Location
{
    T lat;
    T lon;
    T alt;
    // and roughly 20 variables more of type T
};

在我的代码中,Tfloatdouble,具体取决于我需要的精度。有时我需要在这两个结构之间进行转换。因此我想定义一个转换运算符

template<typename A, typename B> operator Location<B> {
    Location<B> ret;
    // cast every variable in *this from type A to type B
    return ret;
}

由于Location中有很多变量,将来很可能需要向结构体中添加更多变量,所以我不想在转换中手动编写每个转换运算符。

因此,我想知道是否有某种自动转换结构中所有变量的方法?

恐怕没有这种办法。我可能会编写模板化的复制构造函数并手动分配每个变量。您现在只需执行一次,然后每次添加新变量时 - IMO 没什么大不了的。

就我个人而言,我从未有过这个用例,但如果该结构中的所有条目都属于同一类型,不应该像下面这样工作吗?

template<typename T>
struct Location {
    T a;
    T b;
    T c;

    template<typename B> operator Location<B>() {
        if constexpr(std::is_same_v<T,B>) {
            return *this;
        }
        Location<B> ret;

        constexpr std::size_t count = sizeof(Location<T>)/sizeof(T);
        static_assert(sizeof(Location<B>)==sizeof(B)*count);
        for (std::size_t i=0;i<count;++i){
            B b;
            T a;
            memcpy(&a, ((char*)this)+i*sizeof(T), sizeof(T));
            b = static_cast<B>(a);
            memcpy(((char*)&ret) + i*sizeof(B), &b, sizeof(B));
        }
        return ret;
    }
};

我很确定那个怪物中的某个地方是 UB 或者至少是内存对齐问题。

这显然不适用于指针或包含指针的 types/structs。

没有好的方法来做到这一点...但这里有一个完全糟糕的方法,永远不要使用它,并且只有在 Location 只包含 T 个实例时才有效。也可能有alignment issues.

template<typename B>
operator Location<B>() const {
    Location<B> ret;
    for (int i = 0; i <= (sizeof(Location<T>) / sizeof(T)); i++) {
        *(&ret.lat + i) = B(*(&lat + i));
    }
    return ret;
}

你无法在本地执行此操作。

您可以编写的一个函数可能在其他上下文(例如比较)中有用,它是 tie/as_tuple 方法:

template<typename T>
struct Location
{
    T lat;
    T lon;
    T alt;
    // and roughly 20 variables more of type T

    auto as_tuple() const { return std::tie(lat, lon, alt /*, ..*/); }

    template <typename T2> operator Location<T2>() const
    {
        return std::make_from_tuple<Location<T2>>(as_tuple());
        // return std::apply([](auto... args){ return Location<T2>{static_cast<T2>(args)...}; },
        //                   as_tuple());
    }
};