【问题标题】:Deduction guides for functions as template parameters函数作为模板参数的推导指南
【发布时间】:2017-08-22 20:12:11
【问题描述】:

We can use std::unique_ptr to hold a pointer allocated with malloc which will be freed appropriately. 但是,生成的std::unique_ptr 的大小将是 2 个指针,一个用于指向对象的指针,一个用于指向删除函数的指针,而不是通常的 1 个指向对象的指针和一个隐式的 delete。正如一个答案指出的那样,可以通过编写一个知道正确删除函数的自定义Unique_ptr 来避免这种情况。这个函数可以使用模板参数来支持任何删除函数,如下所示:

template <class T, void (*Deleter)(T *)>
struct Unique_ptr {
    explicit Unique_ptr(T *t, void (*)(T *))
        : t{t} {}
    ~Unique_ptr() {
        Deleter(t);
    }
    //TODO: add code to make it behave like std::unique_ptr

    private:
    T *t{};
};

template <class T>
void free(T *t) {
    std::free(t);
}

char *some_C_function() {
    return (char *)malloc(42);
}

int main() {
    Unique_ptr<char, free> p(some_C_function(), free); //fine
    Unique_ptr q(some_C_function(), free);             //should be fine
                                                       //with the right
                                                       //deduction guide
}

如果我们可以使用推导指南而不必指定模板参数,那就太好了。不幸的是,我似乎无法正确使用语法。这些尝试编译失败:

template <class T, auto Deleter>
Unique_ptr(T *, Deleter)->Unique_ptr<T, Deleter>;

template <class T, void (*Deleter)(T *)>
Unique_ptr(T *, void (*Deleter)(T *))->Unique_ptr<T, Deleter>;

也可以编写Unique_ptr&lt;free&gt; q(some_C_function()); 来手动指定函数模板参数,但这会在推导T 时产生问题。

编译Unique_ptr q(some_C_function(), free);或Unique_ptr&lt;free&gt; q(some_C_function());的正确演绎指南是什么?

【问题讨论】:

  • 您的唯一指针是否支持数组?如果是,那么你真的不想想要一个演绎指南(无法区分来自new T() 和new T[n] 的指针)
  • std::unique_ptr 通常在删除器为 std::default_delete 时通过特殊化实现。不会有任何开销。

标签: c++ templates c++17 template-argument-deduction


【解决方案1】:

为什么要写自己的unique_ptr?只需将std::unique_ptr 与自定义删除指针一起使用。使用 C++17,这非常简单:

template <auto Deleter>
struct func_deleter {
    template <class T>
    void operator()(T* ptr) const { Deleter(ptr); }
};

template <class T, auto D>
using unique_ptr_deleter = std::unique_ptr<T, func_deleter<D>>;

或者,正如 Yakk 所建议的,更一般地说:

template <auto V>
using constant = std::integral_constant<std::decay_t<decltype(V)>, V>;

template <class T, auto D>
using unique_ptr_deleter = std::unique_ptr<T, constant<V>>;

这会让你:

unique_ptr_deleter<X, free> ptr(some_c_api());

当然,您必须实际编写X,但您没有空间开销。为了用推导指南完成同样的事情,您需要包装函数删除器以将其提升为模板参数:

template <class T, auto D>
Unique_ptr(T*, func_deleter<D>) -> Unique_ptr<T, func_deleter<D> >;

会这样使用:

Unique_ptr ptr(some_c_api(), func_deleter<free>());

我不确定这一定更好,并且您遇到了导致标准没有具有std::unique_ptr 的推导指南的所有相同问题(即:区分指针和数组)。 YMMV。

【讨论】:

  • 第一个版本需要我写unique_ptr_deleter&lt;char, free&lt;char&gt;&gt; ptr(some_C_function());。 The second version我似乎根本无法工作。
  • @nwp 不是free&lt;char&gt;,只是free。
  • 为什么func_deleter被称为_deleter?
  • 具体来说,template &lt;auto f&gt; using constant_t=std::integral_constant&lt;std::decay_t&lt;decltype(f)&gt;, f&gt;; 似乎比func_deleter 更不受限制,更普遍有用。而且更短。 (() 支持来自函数指针的整数常量上的操作符指针。)(和类似的constant value-template natch)
  • 聪明吗?是的。可读吗?嗯……一个简单的malloc_deleter 可能就是这里的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多