3

我试图理解一些导致 PC-Lint 悲伤的 boost 代码,并以一种我认为不合法的 C++ 但在 VS2008 中编译正常的方式使用了friend关键字。

我以为我将朋友理解为声明类和函数的一种方式。我认为在这样的函数定义上使用是不合法的。但是,MSDN 页面非常具体:

友元函数可以在类声明中定义。这些函数是内联函数,就像成员内联函数一样,它们的行为就像是在看到所有类成员之后但在类范围关闭之前(类声明的结尾)立即定义的。

在类声明中定义的友元函数不在封闭类的范围内;它们在文件范围内。

所以我明白这是合法的,如果不寻常的语法。

我不确定它会得到什么,因为声明朋友的正常原因是增加访问权限。但是,结构的成员默认情况下都是公共的,因此这里没有这样的好处。

我是否遗漏了一些深刻的东西,或者这只是一些风格上的提升问题,有人不喜欢在结构体之后放置内联自由函数?

请注意,_InterlockedIncrement 是 Win32 上的内在函数。

# define BOOST_INTERLOCKED_INCREMENT _InterlockedIncrement

struct thread_data_base
{
    long count;
    detail::win32::handle_manager thread_handle;
    detail::win32::handle_manager interruption_handle;
    boost::detail::thread_exit_callback_node* thread_exit_callbacks;
    boost::detail::tss_data_node* tss_data;
    bool interruption_enabled;
    unsigned id;

    thread_data_base():
        count(0),thread_handle(detail::win32::invalid_handle_value),
        interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
        thread_exit_callbacks(0),tss_data(0),
        interruption_enabled(true),
        id(0)
    {}
    virtual ~thread_data_base()
    {}

    friend void intrusive_ptr_add_ref(thread_data_base * p)
    {
        BOOST_INTERLOCKED_INCREMENT(&p->count);
    }
...
};

更新

感谢 Chubsdad 在下面的回答,我想我现在明白了,我对正在发生的事情的总结:

  • 他们希望这些表现得像自由函数,所以你可以编译intrusive_ptr_add_ref(somePtrToThreadData)
  • 如果它们是在结构之后定义的自由函数,它们将在全局命名空间中可见
  • 将它们放在带有friend限定符的结构中意味着它们在结构内的范围内但不是成员函数,因此表现得更像静态函数
  • 依赖于参数的查找意味着它们在使用时会被找到,就好像它们是自由函数一样
    • 上述组合意味着它们的行为就好像它们是使用自由函数语法的虚函数(将显式数据块作为参数而不是在其上调用)
4

2 回答 2

5

在类定义中定义“朋友”函数是非常好的。在这种特殊情况下,由于友元函数采用类型参数thread_data_base,友元函数定义仅在 ADL(参数相关查找)$3.4.2 的情况下可见,当从类定义的词法范围之外调用时

查看Herb Sutter的命名空间和接口原理

于 2010-09-03T01:35:34.463 回答
1

我是否遗漏了一些深刻的东西,或者这只是一些风格上的提升问题,有人不喜欢在结构体之后放置内联自由函数?

您的猜测似乎是最可能的原因:有人想声明一个类外函数,但又将声明保留在类中,因为该函数与类密切相关,因此他们使用诸如此类的神秘语法。为什么他们首先这样做而不是使其成为成员函数是任何人的猜测。

于 2010-09-03T01:14:51.540 回答