c++ - 运算符|| std::variant 的重载

标签 c++ c++17 variant type-erasure

是否可以为 std::variant 重载 operator||,如果替代类型有这样的操作符就使用它,如果替代类型没有定义这样的操作符则抛出异常?

到目前为止,我得到了类似的东西:

template<typename ...Ts>
constexpr bool operator||(std::variant<Ts...> const& lhs, std::variant<Ts...> const& rhs)
{
    return /*no idea */;
}

最佳答案

首先,使用 SFINAE 编写一个包装器,在可能的情况下调用运算符,否则抛出异常:

struct Invalid :std::exception { };

struct Call_operator {
    template <typename T, typename U>
    constexpr auto operator()(T&& a, U&& b) const
        noexcept(std::is_nothrow_invocable_v<std::logical_or<>, T, U>)
        -> decltype(static_cast<bool>(std::declval<T>() || std::declval<U>()))
    {
        return std::forward<T>(a) || std::forward<U>(b);
    }

    [[noreturn]] bool operator()(...) const
    {
        throw Invalid{};
    }
};

然后,使用访问,尊重noexcept:

template <typename T, typename... Ts>
struct is_nothrow_orable_impl
    :std::conjunction<std::is_nothrow_invocable<Call_operator, T, Ts>...> {};

template <typename... Ts>
struct is_nothrow_orable
    :std::conjunction<is_nothrow_orable_impl<Ts, Ts...>...> {};

template<typename ...Ts>
constexpr auto operator||(std::variant<Ts...> const& lhs, std::variant<Ts...> const& rhs)
    noexcept(is_nothrow_orable<Ts...>::value)
    -> decltype(std::visit(Call_operator{}, lhs, rhs))
{
    return std::visit(Call_operator{}, lhs, rhs);
}

( live demo )

关于c++ - 运算符|| std::variant 的重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57267813/

相关文章:

c++ - 为什么将字符串输出到未命名的 std::ofstream 却给我一个十六进制数?

c++ - LoadImage() (Windows) 找不到文件错误

qt - QByteArray 初始化

c++ - 下面的初始化是如何良构的?

C++ 获取 std::variant 当前帮助的类型的 std::typeindex

graphql - Shopify 店面 API : Getting referenced variant with GraphQL

arrays - 使用Delphi从VarArray获取数据

c++ - 列出文件夹中的所有文件返回空列表

c++ - 商业产品的Qt许可证

c++ - 为什么 `std::byte` 是枚举类而不是类?