【问题标题】:Overloading multi-dimensional brackets [duplicate]重载多维括号[重复]
【发布时间】:2016-07-11 02:59:50
【问题描述】:

如何重载多维括号?

假设我有一个类可以让我访问 n 向量空间中的点。例如:

class NSpaceVector {
    private:
        int vectorSpace[8][8][8][8][8][8][8];
    public:        
        const NSpaceVector operator[][][][][][][](int i, int j, int k, int l, int m, int n, int p)const {return vectorSpace[i][j][k][l][m][n][p]; }
        NSpaceVector operator[][][][][][][](int i, int j, int k, int l, int m, int n, int p) {return vectorSpace[i][j][k][l][m][n][p]; }
}
unsigned long & operator [](int i) {return registers[i];}

我想做的是重载括号运算符,以便我可以像这样索引到这个位置:

int main() {
    NSpaceVector nsv; // Assume initializes all to 0
    nsv[2][4][7][4][0][7][6] = 2;
    cout << nsv[2][4][7][4][0][7][6] << endl; //-> 2
    cout << nsv[1][4][7][4][0][7][6] << endl; //-> 0
    return 0;
}

我无法编译它。有任何想法吗?谢谢,基思 :^)

【问题讨论】:

  • 您不能重载多维括号,因为 C++ 中没有这样的运算符。相反,您必须重载单个括号以返回一种代理对象,因为一维括号的每个重载都意味着第二级索引,这将返回另一个代理......等等。
  • 阅读本文以获得更好的方法来执行此操作 operator(): isocpp.org/wiki/faq/operator-overloading#matrix-array-of-array
  • 或者,寻找不同的语法。喜欢nsv(1,2,3,4,5,6,7)nsv[{1,2,3,4,5,6,7}]
  • 严格来说不是重复的,因为这是一个很容易回答的特殊情况:auto&amp; operator[](int i) {return vectorSpace[i]; } - 应该可以按预期工作。

标签: c++ operator-overloading brackets square-bracket


【解决方案1】:

有什么想法吗?

只能选择为每个级别重载operator[](),并让返回类型有另一个operator[]() 重载。


如 cmets 中所述,这通常通过重载调用 operator() 来解决:

int operator()(size_t dim1, size_t dim2, ... size_t dimn);  

【讨论】:

  • 这个答案让我不快。我们有可能将其添加到 C++17 规范中吗?
  • @kmiklas 很抱歉说出事实让您不快。不,使用 c++17 规范 AFAIK 不会对运算符重载语法进行更改,我怀疑您是否会说服 c++ 标准委员会针对该问题对其进行更改。
  • @kmiklas zilch。除非你有时间机器,否则是无穷小。
  • @πάνταῥεῖ:C++17 的运算符重载很可能会发生变化(即通过operator. 进行的智能引用)只是括号下标运算符没有变化。
【解决方案2】:

标准答案是让每个[](从左到右)返回正确嵌套子集的代理,其中最后一个实际上返回对数据的引用。在您的方案中,到目前为止,将嵌套类型模板化以自动化生产是最简单的。

正如神秘的user4581301所说,提供起来要简单得多

nsv(2,4,7,4,0,7,6)

生成所需类的示例模板可能比使用临时代理对象更简单:

template <size_t Width, size_t Depth, typename T=int>
struct SubSpace;

template <size_t Width, typename T>
struct SubSpace<Width,0,T> {
    std::array<T, Width> array;

    T& operator[] (size_t i) { return array[i]; }
    T const& operator[] (size_t i) const { return array[i]; }
};

template <size_t Width, size_t Depth, typename T>
struct SubSpace {
    using Nested = SubSpace<Width, Depth-1, T>;
    std::array<Nested, Width> array;

    Nested& operator[] (size_t i) { return array[i]; }
    Nested const& operator[] (size_t i) const { return array[i]; }
};


using NSpaceVector = SubSpace<8,6>;

int main()
{
    NSpaceVector nsv;
    nsv[2][4][7][4][0][7][6] = 2;
    cout << nsv[2][4][7][4][0][7][6] << endl; //-> 2
}

请注意,目前这不会默认初始化数组成员,但我们仍然可以使用聚合初始化:

    NSpaceVector nsv {}; // value-initialize every element
    nsv[2][4][7][4][0][7][6] = 2;
    cout << nsv[2][4][7][4][0][7][6] << endl; //-> 2
    cout << nsv[2][4][7][4][0][7][5] << endl; //-> 0

另请注意,SubSpace&lt;8,6&gt; 给出了您想要的 8x7 结果,因为深度终止于 0。这可以使用顶级包装器进行清理,但我不愿意在 Depth==1 上终止,并且当一切都出错时有人意外实例化了SubSpace&lt;0,0&gt;


更简单的是,这取决于您是否希望班级中有任何行为,是这样的:

struct OtherSpaceVector {
    int s[8][8][8][8][8][8][8];

    auto operator[] (size_t i) -> decltype(s[i]) { return s[i]; }
};

int main()
{
    OtherSpaceVector osv{};
    osv[2][4][7][4][0][7][6] = 2;
    std::cout << osv[2][4][7][4][0][7][6] << '\n'; 
    std::cout << osv[2][4][7][4][0][7][5] << '\n';
}

它比模板版本更难改变尺寸并且感觉更脆弱,但它仍然适用于您提供的用例。

【讨论】:

    猜你喜欢
    • 2019-02-09
    • 2019-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-26
    • 2013-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多