Search code examples
c++metaprogrammingnoexcept

noexcept operator used on function object always yields true


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:

  1. How can the 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?
  2. Why does this return true, even though none of the lambdas are declared noexcept?

Solution

  • 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 multiple operator()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.