Псевдоним типа C ++ 11 std :: array с операторами - PullRequest
2 голосов
/ 22 марта 2019

У меня есть псевдоним типа c ++ 11 :

using coord = std::array<double, 3>;

Могу ли я определить оператор + для ordin ?Как?Я хотел бы иметь возможность сделать:

coord a, b, c;
a = {1.1, 2.0, 0};
b = {0, -1, 3.5};
c = a + b; // c = {1.1, 1.0, 3.5}

Ответы [ 2 ]

6 голосов
/ 22 марта 2019

Я не рекомендую определять новые операторы для типа STL или любых типов, которые не находятся под вашим контролем.

Я бы предложил вместо этого создать свои собственные типы:

struct coord {
    // reimplement operator[], fill, size, etc.

    friend constexpr auto operator+ (coord const& lhs, coord const& rhs) noexcept -> coord {
        // ...
    }

private:
    std::array<double, 3> _coord;
};

Или вы можете также обойтись, используя операторы и функции-члены, которые уже определены в std::array:

struct coord : private std::array<double, 3> {
    constexpr coord(double a, double b, double c) noexcept :
        array{a, b, c} {}

    using array::operator[];
    using array::begin;
    using array::end;
    using array::fill;
    // other operators...

    friend constexpr auto operator+ (coord const& lhs, coord const& rhs) noexcept -> coord {
        // ...
    }
};

Примечание. Если вы хотите поддерживать структурированное связывание и предлагать доступ к вашему * 1011, подобный кортежу* class, тогда вы должны добавить перегрузки для get и специализировать std::tuple_size и std::tuple_element:

namespace std {
    template<size_t n>
    tuple_element<n, ::coord> {
        using type = double;
    };


    tuple_size<::coord> : integral_constant<size_t, 3> {};
}

template<std::size_t n>
constexpr auto get(coord const& c) noexcept -> double const& {
    return c[n]
}

template<std::size_t n>
constexpr auto get(coord& c) noexcept -> double& {
    return c[n];
}

template<std::size_t n>
constexpr auto get(coord&& c) noexcept -> double&& {
    return std::move(c[n]);
}

template<std::size_t n>
constexpr auto get(coord const&& c) noexcept -> double const&& {
    return std::move(c[n]);
}

Этот код разрешит такой код при включении C ++ 17:

auto my_coord = coord{1.0, 2.0, 3.0};
auto [x, y, z] = my_coord;
1 голос
/ 22 марта 2019

Я хочу добавить, почему вы не должны добавлять operator+ для std::array.Или, в более общем смысле, почему вы должны только добавлять операторы (или, скорее, свободные функции) в пространство имен того типа, с которым они работают (что запрещено в случае std).

Для одного выневозможно поместить оператор в пространство имен A, а затем правильно использовать его в пространстве имен B (без using namespace A;):

namespace A
{
    using coord = std::array<double, 3>; // Putting this in the global namespace doesn't help.

    coord operator+(const coord& right, const coord& left)
    {
        return coord { right[0] + left[0], right[1] + left[1], right[2] + left[2] };
    }
}

auto foo()
{
    A::coord x, y;
    return x + y; // doesn't see the operator
}

https://godbolt.org/z/XUR_NX

Осталось только одно местопоставить оператор это глобальное пространство имен.Если это не доставляет вам неудобств, вот причина, по которой это должно произойти: правила поиска имен довольно скоро сломают вам шею.

Что если мы захотим написать шаблон, который использует ваш operator+?Должно работать нормально, верно?

template<class ... T>
auto add(T ... t)
{
    return (t + ...);
}

https://godbolt.org/z/Ox8_r5

Да, это работает!Ну, , пока кто-то не добавит любой operator+ ближе к шаблону :

namespace A
{
    struct X{};
    void operator+(X, X);

    template<class ... T>
    auto add(T ... t)
    {
        return (t + ...); // won't find the correct operator+ for T=coord
    }
}

https://godbolt.org/z/ctcfxr

На этом поиск имени останавливается operator+.Поскольку ваш правильный (для std::array) отсутствует в namespace std (где std::array), он не может быть найден с помощью ADL (поиск, зависящий от аргумента).В этот момент у вас нет выбора.

...