Использование 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
.
Ответы
Ответ 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]