【问题标题】:Pass 1d or 2d vector to constructor of same class将 1d 或 2d 向量传递给同一类的构造函数
【发布时间】:2019-06-25 01:09:23
【问题描述】:

我即将创建类,处理双精度的二维向量。我想将向量的向量或双精度的简单向量(如果第二维是 1 个元素宽)传递给构造函数。此外,它是用于编辑基础数据的模态对话框,因此,我通过引用传递向量。

一些我想要实现的参考代码:

class TableEditDialog {
    using Table2d = std::vector<std::vector<double>>;

public:
    TableEditDialog(Table2d & data) : m_data( data ) {}
    TableEditDialog(std::vector<double> & data); // ?

private:
    Table2d& m_data;
};

如果传递带有 N 个元素的简单双精度向量,我需要 m_datavector&lt;vector&lt;double&gt;&gt; ,其中包含一个元素的 N 个向量,或者一个包含 N 个元素的向量。

我尝试使用委托构造函数,但没有成功。 我还尝试在第二个构造函数中创建新的临时二维向量,但它打破了通过引用传递来编辑底层数据的想法。

【问题讨论】:

  • 什么是一维向量,而不是一个维数为 1 的二维向量?
  • @user4581301,例如:调用者包含vector&lt;double&gt; = {1, 2, 3},但是当这个数据传递给我的班级时,我希望它被解释为vector&lt;vector&lt;double&gt;&gt; = {{1, 2, 3}}vector&lt;vector&lt;double&gt;&gt; = {{1}, {2}, {3}}

标签: c++ vector


【解决方案1】:

TableEditDialog 设为类模板,以便在构造时指定类型。

template<class T>
class TableEditDialog {
public:
  TableEditDialog(T& data) : m_data( data ) {}
private:
  T& m_data;
};

你也可以制作一个函数来帮助进行类型推断:

template<class T>
TableEditDialog<T> make_table_edit_dialog(T& data) {
  return data;
}

那么你可以这样做:

std::vector<double> d1d;
std::vector<std::vector<double>> d2d;

auto ted1 = make_table_edit_dialog(d1d);
auto ted2 = make_table_edit_dialog(d2d);

编辑:

如果您想将一维数组的情况转换为二维数组,您可以重载一维向量的构造函数并通过将向量复制到其中来初始化m_data

class TableEditDialog {
  using Array1d = std::vector<double>;
  using Array2d = std::vector<Array1d>;
public:
  TableEditDialog(Array2d& data) : m_data( data ) {}
  TableEditDialog(Array1d& data) : m_data(1, data) {}
private:
  Array2d m_data;
};

【讨论】:

  • 感谢您的出色选择。但是另一个问题来了。我们需要不同的代码库来在内部处理 1d 类型和 2d 类型,例如,当我们迭代元素时。有没有办法在构造过程中以某种方式将 1d 案例转换为 2d 案例,因此该类中的所有其他代码库将保持为 2d 向量设计?
  • @DenisGolovkin 对于二维数组情况进行特殊重载可能更容易,将数组展平并将其视为一维数组。您可以使用特殊技巧访问索引:对于大小为width x height 的二维数组,将所有元素放入大小为width x height 的一维数组中,并使用array[width * row + col] 作为一维数组访问元素。
  • @DenisGolovkin 但是如果您想将一维数组转换为二维数组,也可以这样做。我马上更新。
  • 谢谢!这是一个很大的进步。现在这个类可以在一维和二维情况下正确访问和可视化数据。唯一我必须弄清楚的是如何修改底层的data,因为m_data不是参考,而是复制。
  • @DenisGolovkin 您可以将数据结构更改为vector&lt;reference_wrapper&lt;vector&lt;double&gt;&gt;&gt;,以便您实质上持有对基础数据的引用。 std::reference_wrapper 可以在 &lt;functional&gt; 中找到。如果我想到比这更好的东西,我会告诉你的。
【解决方案2】:

您可以将 1d 矢量转换为 2d 矢量存储元素的引用。这种解决方案的唯一缺点是,在完成编辑之前,您不能使用这个 1d 矢量,否则可能会中断。

这里是例子:

TableEditDialog(std::vector<double> & data) {
    std::vector<std::vector<std::reference_wrapper<double>>> result(data.size());
    std::transform(data.begin(), data.end(), result.begin(), [](double& d) {return {{d}};});
}

不过,我没有对此进行测试,您可能需要在 lambda 中使用 {{std::forward(d)}}

剩下的唯一问题是你对 m_data 的定义不同,但访问语义相同,所以你要么需要使用模板代码来访问它,要么使用 std::variant。

【讨论】:

    猜你喜欢
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    • 2016-05-23
    • 2019-08-07
    相关资源
    最近更新 更多