如何在C ++中声明std :: bind的std :: invoke_result?

时间:2019-06-20 10:23:58

标签: c++ c++17

我想用自定义删除器声明std::unique_ptr,该删除器将一些参数绑定到特定函数:

using namespace std::placeholders;
using HandleDeleter = std::invoke_result_t<std::bind, _1, SOME_FLAG>; // !!!
using HandlePtr = std::unique_ptr<handle_t, HandleDeleter>;

void handle_destroy(handle_t *, int flags);
handle_t * raw_handle;

auto deleter = std::bind(handle_destroy, _1, SOME_FLAG);
HandlePtr ptr(raw_handle, deleter);

这是行不通的,因为std::bind本身就是一个巨大的模板结构,没有指定返回类型。

在我的情况下如何正确声明HandleDeleter

2 个答案:

答案 0 :(得分:3)

std::invoke_result_t不是单个可调用对象,而是一个函数模板。因此,您必须选择要传递给decltype的那个,这确实很麻烦。

幸运的是,还有更好的选择:

  1. 使用using deleter_t = decltype(std::bind(handle_destroy, _1, SOME_FLAG));

    unique_ptr ptr(raw_handle, deleter);
    
  2. 对此类使用template-argument-deduction:

    std::bind()

无论如何,由于对使用的函数和参数进行了硬编码,因此通常不使用std::bind()更为简单,并且效率更高。尽管您当然可以自由地仅对部分代码进行硬编码:

  1. 使用lambda代替auto deleter = [](handle_t* p){ handle_destroy(p, SOME_FLAG); }; 。在C ++ 20中,无状态的lambda甚至会变为默认可构造的:

    std::bind
  2. 定义您自己的自定义删除器类,而不使用struct deleter_t { constexpr void operator()(handle_t* p) const noexcept { handle_destroy(p, SOME_FLAG); } };

    devDependencies

答案 1 :(得分:2)

  

这是行不通的,因为std::bind本身就是一个巨大的模板结构,没有指定返回类型。

这是一个提示:您可能使用了错误的工具来完成工作。

我将改用简单的struct

struct HandleDeleter
{
    int _flag;
    void operator()(handle_t* h) const
    {
        handle_destroy(h, _flag);
    }
};

HandlePtr ptr(raw_handle, HandleDeleter{SOME_FLAG});

在现代C ++中不建议使用

std::bind。请改用lambda(或struct)。 std::bind有几个问题excellently explained in this talk by Stephan T. Lavavej “functional: What's New, And Proper Usage"

screenshot from talk