I ran into this by accident, while playing around with the noexcept
operator when trying to implement my own version of std::visit
for educational purposes. This is the code with only the relevant parts:
#include <iostream>
template<typename... Ts>
struct visitor : Ts... { using Ts::operator()...; };
template<typename... Ts>
visitor(Ts...) -> visitor<Ts...>;
int main() {
auto vis1 = visitor {
[](int s) {
},
[](double s) {
}
};
constexpr auto isNoExcept = noexcept(vis1);
std::cout << std::boolalpha << isNoExcept << '\n';
return 0;
}
This always outputs true
for me (gcc and clang).
I have 2 questions:
noexcept
operator even be applied when there are multiple operator()
s, since some might be noexcept
, while others are not? How can there be one answer? What exactly happens here?true
, even though none of the lambdas are declared noexcept
?In noexcept(vis1)
the expression you're checking is vis1
. The evaluation of this expression can't possibly throw an exception, because it doesn't do anything. So this returns true
regardless of the exception specification on any of the functions in the overload set defined by vis1
.
However, if you write noexcept(vis1(42))
, then you are checking whether evaluating the expression vis1(42)
might throw an exception. Since the overload taking an int
is not marked noexcept
, the evaluation may indeed throw an exception, and this returns false
.
To answer your specific question,
How can the
noexcept
operator even be applied when there are multipleoperator()
s?
You're not supposed to apply the noexcept
operator on all the operator()
s at once, but only one specific operator()
at a time as I showed above, and in that case, the compiler simply checks whether the overload that would be picked is marked noexcept
or not.