Использовать "noexcept" в std::function?
Этот код компилируется и запускается, бросая int
:
#include <functional>
void r( std::function<void() noexcept> f ) { f(); }
void foo() { throw 1; }
int main()
{
r(foo);
}
Однако я хотел бы, чтобы компилятор отклонил строку r(foo);
так как r
должен быть передан только noexcept
функция. noexcept
Спецификатор, кажется, игнорируется. Есть ли способ добиться этого?
Редактировать: Этот вопрос отличается от того, должны ли знания о noexcept-ness быть переданы при передаче указателя функции? потому что я прошу средства правовой защиты, особенно в случае std::function
,
1 ответ
Я также наткнулся на эту проблему. Мое решение состояло в том, чтобы использовать делегирующий объект (делегирование функции std::). У делегата есть спецификация "кроме". Это все еще можно улучшить (добавить ход и т. Д.).
Вот оно...
#include <functional>
template <class FuncT>
struct NoExceptDelegate;
template <class R, class ... Args >
struct NoExceptDelegate<R(Args...)>
{
NoExceptDelegate(std::function<R(Args...)>&& callback)
: callback_(move(callback))
{
if (!callback_)
{
throw std::invalid_argument( "NoExceptDelegate requires a valid callback");
}
}
NoExceptDelegate(const NoExceptDelegate& other)
: callback_(other.callback_)
{
}
NoExceptDelegate& operator=(const NoExceptDelegate& other)
{
if (this != &other)
{
callback_ = other.callback_;
}
return *this;
}
NoExceptDelegate(NoExceptDelegate&& other)
: callback_(move(other.callback_))
{
}
NoExceptDelegate& operator=(NoExceptDelegate&& other)
{
callback_ = move(other.callback_);
return *this;
}
template <class...ArgsU>
R operator()(ArgsU&&... args) noexcept
{
return callback_(std::forward<ArgsU>(args)...);
}
private:
std::function<R(Args...)> callback_;
};
Это обычно используется в качестве контракта в асинхронном интерфейсе, чтобы указать, что предоставленный обработчик не должен выдавать, например:
struct Interface
{
virtual void doSomethingAsynchronous(
NoExceptDelegate<void(int)> onCompletionResult) = 0;
//...etc
};
Поскольку клиент является поставщиком обратного вызова, NoExceptDelegate - это обещание поставщика, которое не должно завершиться сбоем. Поставщик должен убедиться, что по крайней мере предоставленная функция std::function является вызываемой.