为什么我要在C++中使用.*运算符?

Ber*_*ard 9 c++ pointer-to-member

我最近发现C++中存在.*运算符(以及密切相关的->*运算符).(见这个问题.)

起初看起来很整洁,但为什么我会需要这样的东西呢?链接问题中的两个答案提供了可以从直接函数调用中受益的人为例子.

在直接函数调用不方便的情况下,可以使用函数对象,就像可以使用的lambda函数一样std::sort.这消除了间接级别,因此比使用更高效.*.

链接的问题还提到了此示例的简化版本:

struct A {
    int a;
    int b;
};

void set_member(A& obj, int A::* ptr, int val){
    obj.*ptr = val;
}

int main()
{
    A obj;
    set_member(obj, &A::b, 5);
    set_member(obj, &A::a, 7);
    // Both members of obj are now assigned
}
Run Code Online (Sandbox Code Playgroud)

但这样做是非常微不足道的(可能更好的做法,因为它更清洁,并且不会对成员造成不必要的限制A):

struct A {
    int a;
    int b;
};

void set_me(int& out, int val){
    out = val;
}

int main()
{
    A obj;
    set_me(obj.b, 5);
    set_me(obj.a, 7);
    // Both members of obj are now assigned
}
Run Code Online (Sandbox Code Playgroud)

总之,指向成员函数的指针可能被函数对象替换,指向成员指针的变量可能被所述变量或函数对象的直接引用所取代.这样做也可以提高代码的效率,因为减少了一个间接.

这个问题只提供了我的结论所代表的例子,所以它没有回答我的问题.

除了接口使用的遗留代码.*(根本就没有选择),我真的想要使用它.*吗?

Dav*_*ett 5

您可以创建指向成员的指针集合并迭代它们.例如:

struct UserStrings
{
    std::string first_name;
    std::string surname;
    std::string preferred_name;
    std::string address;
};

...

std::array<std::string UserStrings::*, 4> str_cols = { &UserStrings::first_name, &UserStrings::surname, &UserStrings::preferred_name, &UserStrings::address };
std::vector<UserStrings> users = GetUserStrings();

for (auto& user : users)
{
    for (auto& column : str_cols)
    {
        SanitizeForSQLQuery(user.*column);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Bernard:但在一般情况下,它会导致代码膨胀.在现实生活中,是否使用运行时参数(上述)或编译时参数(模板)的决定并不容易.因此,关于"通过使用模板更快地制作"的论点过于原始.模板的价格是代码膨胀,在功能较大的情况下可能很大.模板化代码的正确设计涉及知道何时切换到运行时参数化以抑制不必要的代码膨胀.在成员选择方面,指针到成员正是运行时参数化的工具. (2认同)

AnT*_*AnT 5

你的例子太琐碎,无法说明.考虑一点复杂

struct A {
    int a;
    int b;
};

void set_n_members(A objs[], unsigned n, int A::* ptr, int val)
{
  for (unsigned i = 0; i < n; ++i)
     objs[i].*ptr = val;
}

int main()
{
    A objs[100];
    set_n_members(objs, 100, &A::b, 5);
    set_n_members(objs, 100, &A::a, 7);
}
Run Code Online (Sandbox Code Playgroud)

如果int A::* ptr不引入代码膨胀,你会如何重写?