Конструкторы, которые принимают разные размеры массивов - PullRequest
2 голосов
/ 10 октября 2019

Я могу сделать это:

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

Я хотел бы сделать это:

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

Что, конечно, не работает.

Это включаетунаследованный код с множеством 3-х и 4-х элементных двойных массивов. Я хочу создать класс, который содержит 4 двойника из 3 или 4 массивов элементов, и инициализировать 4-й дубль постоянным значением при построении из массива из 3 элементов. Когда я инициализирую из 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){}
}

Есть ли лучшие идеи?

(Как позволяет времяЯ прогоню все сырые массивы, но сейчас я должен разобраться с этим.)

Ответы [ 2 ]

5 голосов
/ 10 октября 2019

Массивы могут быть переданы по ссылке. Если у вас есть

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

, то foo может быть создан только из массива размера 3 или размера 4. Это не позволяет вам принимать указатели, хотя

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

не будет работать,

1 голос
/ 10 октября 2019

Вы можете сделать так, чтобы ваши конструкторы принимали ссылки на массивы:

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...