【问题标题】:Overload std::unique_ptr deleter method using std::enable_if使用 std::enable_if 重载 std::unique_ptr 删除器方法
【发布时间】:2021-11-10 00:07:49
【问题描述】:

我正在尝试为我的std::unique_ptr 编写删除器,并且我想重载删除方法。这是我尝试过的,但编译器抱怨使用std::enable_if_t。代码使用-std=c++20 标志编译。

template <class T>
class custom_deleter
{
public:
    template <class U, std::enable_if_t<std::is_array_v<T>, bool> = true>
    void operator()(U* ptr) { std::cout << "array"; }

    template <class U, std::enable_if_t<!std::is_array_v<T>, bool> = true>
    void operator()(U* ptr) { std::cout << "non-array"; }
};

这是编译器错误:

main.cpp:17:10: error: no type named 'type' in 'struct std::enable_if<false, bool>'
   17 |     void operator()(U* ptr) { std::cout << "non-array"; }
      |          ^~~~~~~~

我不明白这个问题。起初,我以为我缺少 std::enable_if_t 可用的包含或编译标志,但这不是问题所在。任何帮助表示赞赏。

【问题讨论】:

  • 我相信enable_if_t 条件必须依赖于U(或operator() 的某些模板参数)。或者,您可以使用 C++20 中的requires
  • 谢谢,现在才意识到。由于我可以访问 C++20,因此使用 if constexpr 使其更具可读性。

标签: c++ templates c++20 unique-ptr sfinae


【解决方案1】:

SFINAE 需要依赖函数的模板参数。这意味着std::enable_if_t 只能应用于U 而不能应用于类模板T。因此,您需要以某种方式将模板参数T 包含在您的operator()s 中(例如class U = T)或只是if constexpr operator(),因为无论如何您都可以访问

template <class T>
class custom_deleter
{
public:
    template <class U = T>
    void operator()(U* ptr)
    {         
        if constexpr(std::is_array_v<U>)  std::cout << "array"; 
        else if constexpr(!std::is_array_v<U>)  std::cout << "non-array";
    }
};

int main()
{
    custom_deleter<int[2]> arrDel;
    custom_deleter<std::string> strDel;
    return 0;
}

【讨论】:

  • std::is_array/_v 无法将std::array 识别为数组(请参阅this example)。您需要改用custom_deleter&lt;int[]&gt;custom_deleter&lt;int[2]&gt;
  • SFINAE 需要依赖函数的模板参数。
【解决方案2】:

SFINAE 在选择要调用的函数时起作用,但您的条件取决于T,而不是U。实际上不确定这是否是正确的解释,sfinae 让我头晕:P。当您使用 C++20 时,我建议使用 constexpr if 而不是 SFINAE。无论如何,这编译:

#include <iostream>
#include <type_traits>


template <class T>
class custom_deleter
{
public:
    template <class U,class W=T, std::enable_if_t<!std::is_array_v<W>, bool> = true>
    void operator()(U* ptr) { std::cout << "non-array"; }

    template <class U,class W=T, std::enable_if_t<std::is_array_v<W>, bool> = true>
    void operator()(U* ptr) { std::cout << "array"; }

};


int main(){
    custom_deleter<int> p{};
    p("asd");
}

再想一想.. 为什么会有 UT ?你不想用custom_deleter&lt;T&gt; 删除Ts 吗?我想你实际上想要这个:

template <class T>
class custom_deleter
{
public:
    template <class U=T, std::enable_if_t<!std::is_array_v<U>, bool> = true>
    void operator()(U* ptr) { std::cout << "non-array"; }

    template <class U=T, std::enable_if_t<std::is_array_v<U>, bool> = true>
    void operator()(U* ptr) { std::cout << "array"; }

};


int main(){
    custom_deleter<int> p{};
}

【讨论】:

  • 我在示例中删除了很多原始代码以使其更易于阅读,但本质上,删除器将T 存储用于其他目的,因此我最终同时使用@987654331 @ 和 U.
猜你喜欢
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-26
  • 2014-08-29
相关资源
最近更新 更多