首页 > 解决方案 > 不需要括号或引用的成员别名的 C++ 标准方式?

问题描述

假设我们有一个类,也许是一个模板化的固定大小向量:

template <size_t N, typename T>
struct VectorN
{
    T values[N];
}

另外,让我们从一开始就明确表示:不允许#define。我想让 x、y、z、w 等名称可以访问值。其中一种方式(“成员函数”方式)是:

T& x()
{
    assert(N >= 1);
    return values[0];
}

T& y()
{
   assert(N >= 2);
   return values[1];
}
/* etc */

它有效,高效且正确,但它很丑陋,因为它要求您像这样使用它:

//reference alias way
VectorN<4,double> v;
v.x() = 4.4;
v.y() = 12.32;

删除括号会导致“函数作为左操作数”错误。据我所知,与匿名结构建立联盟并不标准。编译器可以在成员之间填充,从而破坏一切。另外,我不知道如何使它与可变(在编译时已知)大小一起工作,无论如何它似乎很危险:

template <size_t N, typename T>
struct VectorN
{
    union
    {
        T values[N];
        struct
        {
            T x,y,z,w;
        }
    }
}

另一种方法是将原始值的引用保留为结构中的变量:

template <size_t N, typename T>
struct VectorN
{
    T values[N];

    T& x, y, z, w;
}

但是它膨胀了我们向量结构的大小,并且出现了另一个问题:如果向量的大小不是 4 怎么办?然后其中一个引用必须是空的,这是可能的,但它有点像癌症和可怕的。使用指针是没用的——它很丑,容易出错,函数方式要好得多。

所以问题是,如何给成员变量做别名,这样它们就可以无缝使用,就像原生结构一样,像这样:

VectorN<3,int> z;
z.x = 0;
z.y = 1;
z.z = 2;
z.w = 3; //fails cause assertion

甚至可以以便携式方式制作吗?

标签: c++

解决方案


我同意 Jarod 关于使用函数调用的可用性/“丑陋”的评论。但只是为了(也对我自己)表明这是可能的,您可以使用隐式转换运算符模拟“无调用”getter。

现在这是否是一个“好主意”是一个非常不同的问题:

template <typename T, std::size_t N, std::size_t I>
struct named_subset {
    using value_type = typename T::value_type;
    T* p;

    static_assert(I < N, "invalid index");

    named_subset(T* p) : p{p} {}

    operator value_type() { return (*p)[I]; }

    named_subset& operator =(value_type const& rhs) {
        (*p)[I] = rhs;
        return *this;
    }
};

template <typename T, std::size_t N>
struct vec_n {
    using value_type = T;
    T values[N];
    named_subset<vec_n, N, 0> x{this};
    named_subset<vec_n, N, 1> y{this};
    named_subset<vec_n, N, 2> z{this};
    named_subset<vec_n, N, 3> w{this};

    T& operator [](std::size_t i) { return values[i]; }
};

(上面的接口被简化了,特别是省略了const重载。)

当然,这会增加结构的大小,因为每个 getter 都需要随身携带一个指向其所有者的指针。我不认为有办法解决这个问题。


推荐阅读