我可以使用std :: pair,但重命名.first和.second成员名称?

Tre*_*key 15 c++ typedef std-pair c++17

我遇到的一个常见设计问题是,我将两个变量捆绑在一起,然后失去了以有意义的方式引用它们的能力.

std::pair<int,int> cords;
cord.first = 0; //is .first the x or y coordinate?
cord.second = 0; //is .second the x or y coordinate?
Run Code Online (Sandbox Code Playgroud)

我考虑过编写基本结构,但后来失去了许多带来的好处std::pair:

  • make_pair
  • 非成员重载运算符
  • 交换
  • 得到
  • 等等

有一种方法来重命名或用于提供一个替代标识符firstsecond数据成员?

我希望利用所有接受的功能std::pair,
但仍然可以通过以下方式使用它们:

std::pair<int,int> cords;  
//special magic to get an alternative name of access for each data member.

//.first and .second each have an alternative name.
cords.x = 1;
assert(cords.x == cords.first);
Run Code Online (Sandbox Code Playgroud)

Nat*_*ica 12

你可以解决这个问题的一种方法是使用std::tie.您可以tie()返回已命名的变量,以便获得良好的名称.

int x_pos, y_pos;

std::tie(x_pos, y_pos) = function_that_returns_pair_of_cords();

// now we can use x_pos and y_pos instead of pair_name.first and pair_name.second
Run Code Online (Sandbox Code Playgroud)

这样做的另一个好处是,如果你改变函数以返回一个元组tie()也将使用它.


使用C++ 17,我们现在具有结构化绑定,允许您将多个变量声明并绑定到函数的返回.这适用于数组,元组/对象对象和结构/类(只要它们满足一些要求).在这种情况下使用结构化绑定允许使用将上面的示例转换为

auto [x_pos, y_pos] = function_that_returns_pair_of_cords();
Run Code Online (Sandbox Code Playgroud)

你也可以

auto& [x_pos, y_pos] = cords;
Run Code Online (Sandbox Code Playgroud)

现在x_pos是一个参考cords.firsty_pos参考cords.second.


Ben*_*ley 6

你可以做免费的功能:

int& get_x(std::pair<int, int>& p) { return p.first; }
int& get_y(std::pair<int, int>& p) { return p.second; }
int const& get_x(std::pair<int, int> const& p) { return p.first; }
int const& get_y(std::pair<int, int> const& p) { return p.second; }
Run Code Online (Sandbox Code Playgroud)


T.C*_*.C. 5

埃里克·尼伯勒(Eric Niebler)的tagged帮助可能在这里。基本思想是,您可以这样创建getter:

struct x_tag {
    template<class Derived, class Type, std::size_t N>
    struct getter {
        Type& x() & { 
            return std::get<N>(static_cast<Derived&>(*this)); 
        }
        Type&& x() && { 
            return std::get<N>(static_cast<Derived&&>(*this)); 
        }
        const Type& x() const & { 
            return std::get<N>(static_cast<const Derived&>(*this)); 
        }
        const Type&& x() const && { 
            return std::get<N>(static_cast<const Derived&&>(*this)); 
        }
    };
};
Run Code Online (Sandbox Code Playgroud)

您可以类似地实现y_tag(只需将成员函数名称更改为y())。然后:

template<class, class, class...> struct collect;
template<class Derived, std::size_t... Ns, class... Tags>
struct collect<Derived, std::index_sequence<Ns...>, Tags...>
      : Tags::template getter<Derived, std::tuple_element_t<Ns, Derived>, Ns>...{};

template<class Base, class... Tags>
struct tagged : Base, collect<tagged<Base, Tags...>, 
                              std::index_sequence_for<Tags...>, Tags...> {
    using Base::Base;
    // extra polish for swap and converting from other tagged's.
};

namespace std
{
    template<typename Base, typename...Tags>
    struct tuple_size<tagged<Base, Tags...>>
      : tuple_size<Base>
    {};

    template<size_t N, typename Base, typename...Tags>
    struct tuple_element<N, tagged<Base, Tags...>>
      : tuple_element<N, Base>
    {};
}
Run Code Online (Sandbox Code Playgroud)

然后

using coord_t = tagged<std::pair<int, int>, x_tag, y_tag>;
Run Code Online (Sandbox Code Playgroud)