我遇到的一个常见设计问题是,我将两个变量捆绑在一起,然后失去了以有意义的方式引用它们的能力。
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
带来的许多好处:
有没有办法为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);
答案 0 :(得分:11)
解决这个问题的一种方法是使用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,我们现在有structured bindings,它允许您声明并将多个变量绑定到函数的返回值。这适用于数组,元组/对象对象和结构/类(只要它们满足一些要求)。在这种情况下使用结构化绑定可以使用将上面的示例转换为
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
的引用。
答案 1 :(得分: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; }
答案 2 :(得分:3)
Eric Niebler的NTSTATUS CModule1::MapUserSection()
{
typedef struct SHARED_SECTION {DWORD i; };
NTSTATUS status = STATUS_SUCCESS;
ULONG Attributes=OBJ_KERNEL_HANDLE | OBJ_FORCE_ACCESS_CHECK;
OBJECT_ATTRIBUTES objectAttributes;
LARGE_INTEGER MaxSize;
SIZE_T ViewSize=sizeof(SHARED_SECTION);
MaxSize.QuadPart=sizeof(SHARED_SECTION);
WCHAR stringBuffer[] = L"\\MySm2";
UNICODE_STRING sectionName;
RtlInitUnicodeString(§ionName,stringBuffer);
InitializeObjectAttributes(&objectAttributes,§ionName,Attributes,NULL,NULL);
status= ZwCreateSection(§ionHandle_,SECTION_ALL_ACCESS,&objectAttributes,&MaxSize,PAGE_READWRITE,SEC_COMMIT,NULL);
status = ZwMapViewOfSection(sectionHandle_, ZwCurrentProcess(), (PVOID *)&pSharedData_, 0, 0, NULL, &ViewSize, ViewShare, 0, PAGE_READWRITE);
//To test the buffer
RtlFillMemory(pSharedData_, '1',ViewSize);
return status;
}
可能会对此有所帮助。基本的想法是你创建这样的getters:
tagged
您可以类似地实现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>
{};
}
答案 3 :(得分:0)
您无法重命名std :: pair&#39;成员,但您可以创建一个具有命名变量的等效类。您可以使用#defines而不是模板。你可以有这个声明:
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 ++模板做到这一点会很好,但我知道没办法做到这一点。它需要某种新的关键字,例如&#34; template&#34;标识符的含义&#34;此模板参数将用于命名模板内的变量,类型或方法。&#34;
答案 4 :(得分:-1)
您可以使用
#define _px first
#define _py second