【问题标题】:Why could the following library function make a call to a nonstatic member fuction without create an object?为什么以下库函数可以在不创建对象的情况下调用非静态成员函数?
【发布时间】:2022-01-08 15:15:55
【问题描述】:

pb_ds(<ext/pb_ds/assoc_container.hpp> 和其他 4 个头文件)是用于某些数据结构(例如红黑树)的 GNU C++ 库。而且我遇到了修改树时应用更新的代码:

PB_DS_CLASS_T_DEC
template<typename Node_Update_>
inline void
PB_DS_CLASS_C_DEC::
apply_update(node_pointer p_nd, Node_Update_*  /*p_update*/)
{
  node_update::operator()(node_iterator(p_nd),
              node_const_iterator(static_cast<node_pointer>(0)));
}

node_update 类的格式如下:

template<class Node_CItr,class Node_Itr,class Cmp_Fn,class _Alloc>
struct my_node_update
{
    typedef my_type metadata_type;
    void operator()(Node_Itr it, Node_CItr end_it)
    {
        //...
    }
};

我对代码node_update::operator()... 感到困惑,我认为它从node_update 类调用了一个非静态成员函数,但没有创建对象。那么调用是如何进行的呢?

【问题讨论】:

  • apply_update也是一个成员函数,或许node_update是一个基类?
  • 没有足够的上下文来做比猜测更多的事情。一个例子:如果这些全大写标识符(PB_DS_CLASS_T_DECPB_DS_CLASS_C_DEC)是宏,那么编译器在预处理后看到的代码可能与我们看到的大不相同。

标签: c++ oop templates gnulib


【解决方案1】:

如果没有看到PB_DS_CLASS_C_DEC 的完整定义,很难准确地知道,但:: 是范围解析运算符,因此它使用qualified name lookup 的规则来更全面地指定在什么范围内编译器应该找到函数operator(),在本例中为node_update

如果node_updatePB_DS_CLASS_C_DEC 的基类、命名空间、静态成员或什么,则不清楚没有更多上下文。

我确实找到了与您粘贴的代码几乎相同的代码here

看起来像:

PB_DS_CLASS_T_DEC
template<typename Node_Update_>
inline void
PB_DS_CLASS_C_DEC::
apply_update(node_pointer p_nd, Node_Update_*)
{
  Node_Update_::operator()(node_iterator(p_nd, this),
               node_const_iterator(0, this));
}

如果您的代码确实是一个错误,即您的代码有 node_update 而不是 Node_Update_,那么他们会指示编译器在模板类型 Node_Update_ 中使用 operator(),这可能是根据传递的参数推断出来的申请更新。

从上面的 repo 中,apply_update 是私有的,并且总是将 this 作为第二个参数传递给 node_update 类型,该类本身是模板化的,并且也是从其公开继承的。

所以最终结果是Node_Update_ 总是看起来是一个基类,并且他们指定了专门调用operator() 的基类。

【讨论】:

    猜你喜欢
    • 2012-02-17
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2011-10-17
    • 1970-01-01
    • 2015-01-26
    • 1970-01-01
    • 2016-10-13
    相关资源
    最近更新 更多