什么时候在 C++ 中解析函数模板?

When are function templates resolved in c++?

我是一名新手 c++ 程序员,我一直在尝试通过阅读多本有关该语言的书籍来了解更多关于该语言的知识。我正在阅读的一本书中有一节讨论智能指针如何使用用户提供的自定义删除器的不同策略(即唯一指针通过其第二个模板参数采用自定义删除器,而共享指针通过它一个正常的 function/constructor 参数) 我对这一段感到很困惑

Although we don’t know how the library types are implemented, we can infer that shared_ptr must access its deleter indirectly. That is the deleter must be stored as a pointer or as a class that encapsulates a pointer. We can be certain that shared_ptr does not hold the deleter as a direct member, because the type of the deleter isn’t known until run time. Indeed, we can change the type of the deleter in a given shared_ptr during that shared_ptr’s lifetime. We can construct a shared_ptr using a deleter of one type, and subsequently use reset to give that same shared_ptr a different type of deleter. In general, we cannot have a member whose type changes at run time. Hence, the deleter must be stored indirectly.

这里指出删除器类型直到 运行 时间才知道,但我认为所有模板都在编译时解析,所以我可以看到共享指针 class 使用一些东西like void (*del)(T* p) 其中del指向传递的删除器,T是共享指针指向的对象的值类型。那么在这种情况下,类型在编译期间不是已知的吗? 如果有人也可以向我提供他们关于共享指针 class 如何实现删除指针的想法,(以防我错了,我确定是这样)谢谢

如果 shared_ptr 使用了您提到的类型的删除器 ((*del)(T* p)),这将排除使用函数对象甚至绑定成员函数指针的可能性。相反,我确信它使用类似于 std::function 的东西来存储删除器。删除器表示有效 erases 类型,只剩下它知道可以用 T.

类型的单个参数调用的东西

这节好像主要讲删除器存放在什么地方。要在实际 std::shared_ptr<T> 对象中存储已知类型的删除器,需要在编译时知道其具体类型。这种类型很可能是

void (*deleter)(T*);

但是,std::shared_ptr<B> 其中 BDpublic 基可以用 D* 构造,例如:

struct B {};
struct D: B {};
std::shared_ptr<B>(new D);

为了使上述代码正常工作,std::shared_ptr<B> 需要为删除器存储一个 void (*)(D*)。但是,函数指针类型不会相互转换。

因此,结论是 std::shared_ptr<T> 将删除器存储在维护记录中,它无论如何都需要保留以处理引用计数。该记录可能包含一个合适的对象,其中包含实际的删除者。例如,它可以包含一个特定于类型 D 但被所有 std::shared_ptr<T> 共同使用的记录。这条记录到底是什么样子,我不知道,似乎要处理它的所有要求并不是一件容易的事。草稿可能如下所示:

struct shared_ptr_count_record {
    virtual void destroy(void* ptr) = 0;
    // something else
};
template <typename D>
struct shared_ptr_deleter
    : shared_ptr_count_record {
    // something else
    void destroy(void* ptr) override {
        delete static_cast<D*>(ptr);
    }
};
template <typename T>
class shared_ptr {
    shared_ptr_count_record* record;
public:
    template <typename C>
    shared_ptr(C* ptr): record(new shared_ptr_deleter<C>(ptr)) {}
    ~shared_ptr() {
         if (this->record->release()) {
            this->record->destroy(this->get());
         }
    }
    // some other stuff
};

也就是说,函数模板本身是在编译时创建的。但是,一个std::shared_ptr<T>只能知道实际使用的deleter函数要到运行-time.