如何将boost::intrusive_ptr用于类模板中的私有嵌套类

How to use boost::intrusive_ptr for private nested class within class template

本文关键字:嵌套 用于 boost intrusive ptr      更新时间:2023-10-16

假设我有一个list类:

template<typename T>
class list {
    ...
private:
    class node {
        ...
    private:
        std::size_t refcount_;
        // friends of node because accessing private member refcount_
        friend void intrusive_ptr_add_ref(const node* p) noexcept;
        friend void intrusive_ptr_release(const node* p) noexcept;            
    };
    // friends of list because accessing private nested class node
    friend void intrusive_ptr_add_ref(const node* p) noexcept;
    friend void intrusive_ptr_release(const node* p) noexcept;
    boost::intrusive_ptr<node> node_{new node};
};
template<typename T>
void intrusive_ptr_add_ref(const typename list<T>::node* p) noexcept
{ ... }
template<typename T>
void intrusive_ptr_release(const typename list<T>::node* p) noexcept
{ ... }
list<int> xs;  // error

上面的代码没有编译。错误为intrusive_ptr_add_ref(list<int>::node const*)intrusive_ptr_release(list<int>::node const*)的未定义符号。

我认为问题可能是我在listnode中将非模板函数声明为友元,但我定义的是函数模板。那么,正确的方法是什么呢?

这是内联好友定义大放异彩的场合之一:

在Coliru上直播

#include <iostream>
#include <boost/intrusive_ptr.hpp>
template<typename T> class list {
    class node {
        std::size_t mutable refcount_;
        // friends of list because accessing private nested class node
        friend void intrusive_ptr_add_ref(node const* p) noexcept {
            p->refcount_ += 1;
        }
        friend void intrusive_ptr_release(node const* p) noexcept {
            if (--p->refcount_)
                return;
            std::cout << "freeing node " << static_cast<void const*>(p) << "n";
        }
    };
    boost::intrusive_ptr<node> node_{new node};
};
int main() {
    list<int> xs;
}

打印

freeing node 0x19b7c20

或类似

奖励积分

如果你想走详细的路线,我建议最明智的方法是在Node类型上参数化基本模板,而不是列表元素(因为部分专业化不适用于函数模板)。

以下内容也有效:

在Coliru上直播

template <typename Node, typename = typename Node::is_my_list_impl_nodetype> void intrusive_ptr_add_ref(Node const*) noexcept;
template <typename Node, typename = typename Node::is_my_list_impl_nodetype> void intrusive_ptr_release(Node const*) noexcept;
template<typename T> class list {
    class node {
        using is_my_list_impl_nodetype = std::true_type;
        std::size_t mutable refcount_;
        // friends of list because accessing private nested class node
        friend void intrusive_ptr_add_ref<node, std::true_type>(node const* p) noexcept;
        friend void intrusive_ptr_release<node, std::true_type>(node const* p) noexcept;
    };
    boost::intrusive_ptr<node> node_{new node};
};
template<typename Node, typename>
void intrusive_ptr_add_ref(Node const* p) noexcept {
    p->refcount_ += 1;
}
template<typename Node, typename>
void intrusive_ptr_release(Node const* p) noexcept {
    if (--p->refcount_)
        return;
    std::cout << "freeing node " << static_cast<void const*>(p) << "n";
}

如果在使用其他addref/release方法的翻译单元中使用了更具侵入性的指针,那么is_my_list_impl_nodetype上的整个SFINAE是为了防止打开模板创建不明确的重载。