std::visit 相对于 if-else 的优势

The advantage of std::visit over if-else

我发现 std::visit 可以按以下方式使用:

    std::visit([](auto&& arg) {
        using T = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<T, int>)
            std::cout << "int with value " << arg << '\n';
        else if constexpr (std::is_same_v<T, std::string>)
            std::cout << "std::string with value " << std::quoted(arg) << '\n';
        else 
            static_assert(always_false_v<T>, "non-exhaustive visitor!");
    }, v);

但是,我想我也可以只使用

    if(auto x = std::get_if<int>(&v))
        std::cout << " is int " << *x << std::endl;
    else if(auto x = std::get_if<std::string>(&v))
        std::cout << " is String " << *x << std::endl;
    else
        std::cout << "non-exhaustive visitor!" << std::endl;

我现在看到的唯一缺点是当我的匹配不详尽时,我没有静态消息。使用 std::visit 还有其他我没有看到的优势吗?

Is there any other advantage of using std::visit that I am not seeing?

是的。使用 std::visit,您可以使用内置函数重载解析,而不是手动匹配所有类型:

template<typename... Fs> struct Overload: Fs... { using Fs::operator()...; };
template<typename... Fs> Overload(Fs...) -> Overload<Fs...>;

static_assert(visit(Overload{
    [](int) { return "int"; },
    [](std::string_view) { return "string_view"; },
    [](auto) { return "something else"; }
}, std::variant<int, std::string_view, bool, double>{42}) == "int"sv);

此外,visit 可能会因为只有一种类型匹配而编译成更快的代码,但应该检查 ifs 版本是否优化了它的多个匹配。

更新

正如@Quentin 在评论中提到的,

unlike the manual if ladders, an overload will be selected not if it is an exact match, but merely if it is callable (via conversions if needed)

如果存在不需要转换的过载,此技术应该会有所帮助:

[](std::same_as<int> auto) {} // C++20

template<typename T, typename U> using SameAs = std::enable_if_t<std::is_same_v<T, U>>;

[](auto t, SameAs<decltype(t), int>* = 0) {} // C++17