我可以使用std::pair,但是重命名.first和.second成员名吗?
Can I use std::pair, but rename .first and .second member names?
我遇到的一个常见的设计问题是,我将两个变量捆绑在一起,然后失去了以有意义的方式引用它们的能力。
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?
我考虑过写基本结构体,但这样我就失去了std::pair
带来的很多好处:
- make_pair
- 非成员重载操作符
- 得到
- 等。
是否有一种方法来重命名或提供first
和second
数据成员的替代标识符?
我希望利用所有接受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);
解决这个问题的一种方法是使用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
这样做的另一个好处是,如果您更改函数以返回元组,tie()
也可以使用。
在c++ 17中,我们现在有了结构化绑定,允许你声明和绑定多个变量到函数的返回值。这适用于数组、元组/对类对象和结构/类(只要它们满足某些要求)。在本例中使用结构化绑定,让我们将上面的示例转换为
auto [x_pos, y_pos] = function_that_returns_pair_of_cords();
你也可以做
auto& [x_pos, y_pos] = cords;
,现在x_pos
是对cords.first
的引用,y_pos
是对cords.second
的引用
你可以创建自由函数:
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; }
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));
}
};
};
您可以类似地实现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>
{};
}
然后using coord_t = tagged<std::pair<int, int>, x_tag, y_tag>;
您不能重命名std::pair的成员,但是您可以创建一个具有命名变量的等价类。您可以使用#define代替模板。你可以这样声明:
DefinePair(Dimensions, int, Height, int, Width);
Dimensions dimensions(3, 4);
cout << dimensions.mHeight;
,它与std::pair不同,但在保留命名的同时,为您提供了人们希望从std::pair声明的便利性。
有很多方法来构造它——你可以继承std::pair,然后公开命名变量作为对第一个和第二个的引用,如果你需要插入一些接受成对的东西。但最简单的实现是这样的:
#define DefinePair(StructName, FirstType, FirstName, SecondType, SecondName)
struct StructName {
FirstType m##FirstName;
SecondType m##SecondName;
StructName(FirstType FirstName, SecondType SecondName)
: m##FirstName(FirstName),
m##SecondName(SecondName)
{}
};
如果我们能用c++模板做到这一点就好了,但我知道没有办法做到。它需要一些新的关键字,比如"template",其中的标识符表示"这个模板参数将用于命名模板内的变量、类型或方法"。
可以使用
#define _px first
#define _py second
相关文章:
- C++算法标头中,为什么要使用 "!(val < *first)" ?
- 为什么当我为 for(auto& it : myUnorderedMap) {... = std::move(it.second)} 时,我会得到一个 const 引用?
- 迭代嵌套映射与范围为循环:没有名为"first"的成员
- 为什么 std::set.erase(first, last) 会影响从中获取 (first, last) 的容器?
- 为什么 std::d istance() 对于 std:list:<int>:itrator 在 last 在 first 之前时不返回负数?
- c std :: vector迭代器构造函数,first == last
- 如何声明pair<int,int>::first
- 自动,错误:MAP ITERATOR没有名为“ First”的成员
- "Node<T*> *first"和"Node<T> *first"有什么区别?
- 为什么 std::find_if(first, last, p) 不通过引用获取谓词?
- 我怎样才能保持'first'和'second'用结构替换 std::p air?
- 从 iterator.first 获取价值
- 使用 Qt 创建器时出错:"multiple definition" "first defined here"
- Spirit Qi First Parser
- 为什么"begin/end"与"first/last"的差异?
- c++ in Depth First Search
- 队列返回错误的 pair.first 值
- 在 boost::lambda 中表达 _1.second->pair().first == r
- 是否可以在C++中使用命名变量(例如,键和值)而不是 .first 和 .second 进行 std::map<> "for element : container" 迭代?
- 我可以使用std::pair,但是重命名.first和.second成员名吗?