如何同时更新结构的多个字段?

Hra*_*yan 5 c++ struct field accessor

假设我有一个结构

struct Vector3 {
    float x;
    float y;
    float z;
};

Run Code Online (Sandbox Code Playgroud)

注意sizeof(Vector3)必须保持不变。

编辑:我对没有二传手的解决方案感兴趣。

不要让我们创建该 struct 的实例Vector3 pos。我如何能实现我的结构,所以我可以有这样的事情pos.xy = 10 // updates x and y还是pos.yz = 20 // updates y and zpos.xz = 30 // updates x and z

Hum*_*ler 1

由于您的类型是标准布局,因此我认为按照 C++ 标准执行此操作的唯一合法union方法是使用包含具有自定义定义的子对象的a operator=

使用union,您可以查看活动成员的通用首字母序列,前提是所有类型都是标准布局类型。因此,如果我们精心制作一个共享相同公共成员的对象(例如,float顺序相同的 3 个对象),那么我们可以在它们之间“混合”,而不会违反严格别名。

为了实现这一点,我们需要创建一堆成员,这些成员都具有相同顺序、标准布局类型的相同数据。

作为一个简单的示例,让我们创建一个基本的代理类型:

template <int...Idx>
class Vector3Proxy
{
public:

    // ...

    template <int...UIdx, 
              typename = std::enable_if_t<(sizeof...(Idx)==sizeof...(UIdx))>>
    auto operator=(const Vector3Proxy<UIdx...>& other) -> Vector3Proxy&
    {
        ((m_data[Idx] = other.m_data[UIdx]),...);
        return (*this);
    }

    auto operator=(float x) -> Vector3Proxy&
    {
        ((m_data[Idx] = x),...);
        return (*this);
    }

    // ...

private:

    float m_data[3];
    template <int...> friend class Vector3Proxy;
};
Run Code Online (Sandbox Code Playgroud)

在此示例中,并未使用 的所有成员m_data- 但它们的存在是为了满足“公共初始序列”要求,这将允许我们通过union.

这可以根据您的需要进行构建;float单组件运算符的转换、算术支持等。

使用这样的类型,我们现在可以Vector3从这些代理类型构建对象

struct Vector3
{
    union {
        float _storage[3]; // for easy initialization
        Vector3Proxy<0> x;
        Vector3Proxy<1> y;
        Vector3Proxy<2> z;
        Vector3Proxy<0,1> xy;
        Vector3Proxy<1,2> yz;
        Vector3Proxy<0,2> xz;
        // ...
    };
};
Run Code Online (Sandbox Code Playgroud)

然后可以轻松地使用该类型一次分配多个值:

Vector3 x = {1,2,3};

x.xy = 5;
Run Code Online (Sandbox Code Playgroud)

或者将一个零件的组件分配给另一零件:

Vector3 a = {1,2,3};
Vector3 b = {4,5,6};

a.xy = b.yz; // produces {5,6,3}
Run Code Online (Sandbox Code Playgroud)

Live Example

该解决方案还确保sizeof(Vector3)不会改变,因为所有代理对象的大小相同。


注意:union在 C++ 中,将 a与匿名s 一起使用是无效的struct,尽管某些编译器支持它。因此,尽管将其重写为:

union {
    struct {
        float x;
        float y;
        float z;
    }; // invalid, since this is anonymous
    struct {
        ...
    } xy;
}
Run Code Online (Sandbox Code Playgroud)

这在标准 C++ 中无效,并且不是可移植的解决方案。