具有运算符的std :: array的C ++ 11类型别名

时间:2019-03-22 14:38:53

标签: c++ c++11 typedef

我有一个 c ++ 11类型别名

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

我可以为 coord 定义运算符 + 吗?怎么样?我希望能够做到:

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 个答案:

答案 0 :(得分:6)

我不建议为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 {
        // ...
    }
};

注意:如果要支持结构化绑定并提供类似元组的访问coord类的权限,则必须为get添加重载,并专门化std::tuple_sizestd::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 :(得分:1)

我想补充一下为什么您不应该为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 stdstd::array在)中,因此ADL(依赖于参数的查找)无法找到它。届时您将失去选择。