Как объявить std :: invoke_result из std :: bind в C ++? - PullRequest
1 голос
/ 20 июня 2019

Я хочу объявить 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 ]

3 голосов
/ 20 июня 2019

std::bind - это не один вызываемый объект, а шаблон-функция.Таким образом, вам придется выбрать, какой из них передать на std::invoke_result_t, что действительно грязно.

К счастью, есть лучшие альтернативы:

  1. Использование decltype:

    using deleter_t = decltype(std::bind(handle_destroy, _1, SOME_FLAG));
    
  2. Используйте шаблон-аргумент-вывод для класса:

    unique_ptr ptr(raw_handle, deleter);
    

В любом случае, вообще не использовать std::bind()проще и эффективнее из-за жесткого кодирования используемой функции и аргумента.Хотя вы, безусловно, можете использовать только часть с жестким кодом:

  1. Используйте лямбду вместо std::bind().В C ++ 20 лямбда без сохранения состояния даже станет конструируемой по умолчанию:

    auto deleter = [](handle_t* p){ handle_destroy(p, SOME_FLAG); };
    
  2. Определите свой собственный класс для удаления вместо использования std::bind:

    struct deleter_t {
        constexpr void operator()(handle_t* p) const noexcept {
            handle_destroy(p, SOME_FLAG);
        }
    };
    
2 голосов
/ 20 июня 2019

И это не работает, потому что std::bind - чудовищная конструкция шаблона сама по себе с неопределенным типом возврата.

Это подсказка: вы, вероятно, используете не тот инструмент для работы.

Я бы использовал простое struct вместо:

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

HandlePtr ptr(raw_handle, HandleDeleter{SOME_FLAG});

std::bind не рекомендуется в Modern C ++. Вместо этого используйте лямбды (или структуры). std::bind имеет несколько проблем превосходно объяснил в этом выступлении Стефан Т. Лававей «Функциональность: что нового и правильное использование» .

screenshot from talk

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...