【问题标题】:Constructors that take different sizes of arrays采用不同大小数组的构造函数
【发布时间】:2020-02-08 06:54:23
【问题描述】:

我可以这样做:

struct foo{
    foo(std::array<double, 3>){}
    foo(std::array<double, 4>){}
}

我想这样做:

struct foo{
    foo(double A[3]){}
    foo(double A[4]){}
}

这当然行不通。

这涉及带有大量 3 和 4 元素双精度数组的遗留代码。我希望构造一个包含 3 个或 4 个元素数组的 4 个双精度的类,并在从 3 元素数组构造时用一个常量值初始化第 4 个双精度。当我从一个 4 元素数组初始化时,我只是复制了 4 个元素。

所以,我想让构造函数识别:

double something[3];

来自:

double something_else[4];

我能想到的最好的就是在构造函数中再添加一个参数来区分两者。

class foo{
    foo(double A[4], bool only_3 = false){}

    foo(double *A, size_t n = 4){}
}

有更好的想法吗?

(如果时间允许,我会排除所有原始数组,但现在我必须处理它。)

【问题讨论】:

    标签: c++ arrays constructor


    【解决方案1】:

    你可以让你的构造函数接受对数组的引用:

    struct foo {
        foo(const double (&A)[3]) {}
        foo(const double (&A)[4]) {}
    };
    

    如果功能足够相似,您可以制作一个同时接受两个版本的模板:

    struct foo {
        template<size_t N, std::enable_if_t<N == 3 || N == 4, bool> = true>
        constexpr foo(const double (&A)[N]) noexcept {
            std::copy(std::begin(A), std::end(A), values);
            if constexpr(N == 3) values[3] = ... // some constant;
        }
    
        double values[4];
    };
    

    如果您需要接受在编译时已知大小的动态分配数组 (double*),您可以使用标签创建构造函数模板来断言所使用的大小是可接受的。

    struct foo {
        template<size_t N, std::enable_if_t<N == 3 || N == 4, bool> = true>
        struct size_tag_t {};
    
        // convenience tag instances
        static constexpr size_tag_t<3> three_tag{};
        static constexpr size_tag_t<4> four_tag{};
    
        template<size_t N>
        constexpr foo(const double* A, size_tag_t<N>) noexcept {
            std::copy(A, A + N, values);
            if constexpr(N == 3) values[3] = ... // some constant;
        }
    
        double values[4];
    };
    
    //...
    constexpr size_t THREE = 3;
    double* da3 = new double[THREE];
    foo pthree1(da3, foo::size_tag_t<THREE>{});
    // or
    foo pthree2(da3, foo::three_tag);
    

    【讨论】:

      【解决方案2】:

      数组可以通过引用传递。如果你有

      struct foo{
          foo(double (&A)[3]){}
          foo(double (&A)[4]){}
      };
      

      那么foo 只能从大小为 3 或大小为 4 的数组构造。这确实会阻止您接受指针

      double bar = new double[4];
      foo f(bar);
      

      不会工作。

      【讨论】:

      • 我会对此进行修改,看看它会把我带到哪里。不幸的是它杀死了指针。
      • @ttemple 您可以为指针添加重载,只是您必须在其中编写逻辑以处理大小不正确的数组。
      • 如果我添加 foo(double *p) 它会抓住一切。添加它以便其他人仍然被调用的正确方法是什么?
      • @ttemple 这有点棘手。您需要做的是告诉编译器仅在传入的东西实际上是指针而不是可以衰减为指针的数组时才使用指针重载。为此,您需要将构造函数设为模板并使用 SFINAE。你可以在这里看到工作:coliru.stacked-crooked.com/a/471aa48d5247f3d9
      猜你喜欢
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多