Подтвердить что ты не робот

Использование noexcept в качестве модификатора лямбда или ограничения параметра

Можно ли применить модификатор noexcept к выражению лямбда? Если да, то как?

Может ли noexcept сделать ограничение на аргумент функции? Например, что-то вроде следующего кода, где смысл заключается в том, что функция обратного вызова должна быть noexcept?

//probably not valid code - I'm just trying to express the idea
void f_async(std::function<void (int) noexcept> callback) noexcept
{
    ...
}

Это может быть почти выполнено с помощью следующего кода, но мне интересно, есть ли способ использовать что-то вроде вышеупомянутой альтернативы.

void f_async(std::function<void (int)> callback)
    noexcept(callback(std::declval<int>()))
{
    ...
}

Проблема здесь состоит в том, что f_async может быть noexcept(false), если обратный вызов noexcept(false) - я хочу сделать более сильное утверждение о том, что f_async всегда noexcept, что означает, что он доступен только при использовании a noexcept.

4b9b3361

Ответ 1

Можно ли применить модификатор noexcept к выражению лямбда? Если да, то как?

Добавьте noexcept после круглой скобки:

[](Args args) noexcept { ... }

Может ли noexcept быть ограничено на аргумент функции?

Да, используйте enable_if:

template <typename F>
auto f_async(const F& func) noexcept 
        -> typename std::enable_if<noexcept(func(0))>::type {
    func(0);
}

int main() {
    f_async([](int x) noexcept {});
    f_async([](int x) {}); // <- this line won't compile
}

Однако, этот метод не может работать непосредственно в g++ 4.7 (он работает в clang++ 3.2), потому что он не может поканить выражение noexcept:

3.cpp: 5: 6: извините, не реализовано: mangling noexcept_expr

Вы можете обходным путем использовать оболочку struct:

template <typename F, typename... Args>
struct EnableIfNoexcept 
        : std::enable_if<noexcept(std::declval<F>()(std::declval<Args>()...))> {};

template <typename F>
auto f_async(const F& func) noexcept -> typename EnableIfNoexcept<F, int>::type {
    func(0);
}

Ответ 2

Относительно первого вопроса:

Может ли модификатор noexcept применяться к выражению лямбда? Если да, то как?

Да, просто добавьте спецификацию исключения после списка параметров:

[] (int i) noexcept { return i * 1; };
//         ^^^^^^^^

В соответствии с параграфом 5.1.2/5 стандарта С++ 11:

Тип замыкания для лямбда-выражения имеет открытый оператор вызова функции (13.5.4), параметры которого и тип возвращаемого значения описываются параметром-объявления-объявления-лямбда-выражения, а trailingreturn- типа соответственно. Этот оператор вызова функции объявляется const (9.3.1) тогда и только тогда, когда лямбда-выражения Параметр-объявление-предложение не следует mutable. Он не является ни виртуальным, ни объявленным неустойчивый. Аргументы по умолчанию (8.3.6) не должны указываться в объявлении параметра-объявления lambda-declarator. Любая спецификация исключения, указанная в лямбда-выражении, применяется к соответствующей функции вызов оператора. Атрибут-спецификатор-seq в лямбда-деклараторе относится к типу соответствующего оператор вызова функции. [Примечание. Имена, указанные в лямбда-деклараторе, рассматриваются в контексте в который появляется лямбда-выражение. -end note]