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

时间:2015-09-15 16:08:04

标签: 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?

我考虑过编写基本结构,但后来我失去了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);

5 个答案:

答案 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(&sectionName,stringBuffer); InitializeObjectAttributes(&objectAttributes,&sectionName,Attributes,NULL,NULL); status= ZwCreateSection(&sectionHandle_,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