容器类ValueContainer

2025-07-13更新于 2025-08-12161 字11 分钟C++

该容器类的作用

该容器类用于在传值时包裹数据,当数据不为空值时可以调用ifTrueDo函数传入lambda,lambda函数可以接受当前ValueContainer包裹的数据作为参数传递,你可以使用ValueContainer的链式调用方法来链式调用各种数据

cpp
#pragma once
#include <QString>
#include <functional>
#include <type_traits>
#include <optional>

template<typename V>
class ValueContainer {
private:
    //test
    std::optional<V> v;
    QString reason;
public:
    ValueContainer(V value){
        if constexpr (std::is_pointer_v<V>) {
            v = value ? std::make_optional(value) : std::nullopt; // 如果 V 是指针类型,检查是否为 nullptr
        } else {
            v = std::make_optional(std::move(value)); // 对于非指针类型,直接存储值
		}
    }
    ValueContainer() = default;

    // 移动构造函数
    ValueContainer(ValueContainer&& other) noexcept
        : v(std::move(other.v)), reason(std::move(other.reason)) {
		other.v.has_value() ? other.v.reset() : void(); // 清空源对象的值
    }

    // 移动赋值运算符
    ValueContainer& operator=(ValueContainer&& other) noexcept {
        if (this != &other) {
            v = std::move(other.v);
            reason = std::move(other.reason);
			other.v.has_value() ? other.v.reset() : void(); // 清空源对象的值
        }
        return *this;
    }
	// 禁用拷贝构造函数和拷贝赋值运算符

    operator bool() const {
        if constexpr (std::is_pointer_v<V>) { // 仅当 V 是指针类型时应用
            return v.has_value() && v.value() != nullptr;
        }
        else {
            return v.has_value();
        }
    }
    operator V() const {
        return v.value();
    }
    void setReason(QString reason) {
        this->reason = std::move(reason);
    }
    void setValue(V value) {
        v = std::move(value);
    }
    bool isEmpty() const {
        if constexpr (std::is_pointer_v<V>) {
            return !v.has_value() || v.value() == nullptr;
        }
        else {
            return !v.has_value();
        }
    }
    /// <summary>
	/// 当有值时执行 lambda 函数
    /// </summary>
    /// <typeparam name="F">传入的执行方法</typeparam>
    /// <param name="lambda">传入的执行方法</param>
    /// <returns>自动返回或者不返回在内部处理</returns>
    template<typename F>
    auto ifTrueDo(F lambda) -> std::invoke_result_t<F, V&> {
        using ReturnType = std::invoke_result_t<F, V&>;
        if (v.has_value()) {
            return lambda(*v);
        }
        if constexpr (!std::is_void_v<ReturnType>) {
            return ReturnType{};
        }
    }
    template<typename F1, typename F2>
    auto execute(F1 ifHasValue, F2 ifNoValue) -> std::invoke_result_t<F1, V&> {
        using ReturnType = std::invoke_result_t<F1, V&>;
        if (v.has_value()) {
            return ifHasValue(*v);
        }
        else {
            ifNoValue();
            if constexpr (!std::is_void_v<ReturnType>) {
                return ReturnType{};
            }
        }
    }
    V getValue() const {
        return v.value();
    }
    V getValue(V defalt) const {
        return v.value_or(defalt);
    }
    V getValue(std::function<V()> lambda) const {
        return v.has_value() ? *v : lambda();
    }
    V&& moveValue() {
        return std::move(v.value());
    }
    QString getReason() const {
        return reason;
    }
    /// <summary>
    /// 对容器中的值进行转换,并返回一个新的 ValueContainer。
    /// 如果当前容器为空,则返回一个空的 ValueContainer。
    /// </summary>
    /// <typeparam name="F">转换函数类型</typeparam>
    /// <returns>包含转换后值的新 ValueContainer</returns>
    template<typename F>
    auto map(F lambda)&& { // 注意这里是右值引用,实现零拷贝
        using ResultType = std::invoke_result_t<F, V&>;
        if (v.has_value()) {
            return ValueContainer<ResultType>(lambda(*v));
        }
        else {
            ValueContainer<ResultType> newContainer;
            newContainer.setReason(reason); // 传递reason
            return newContainer;
        }
    }
    /// <summary>
    /// 对容器中的值进行转换,并返回一个新的 ValueContainer。
    /// 如果当前容器为空,则返回一个空的 ValueContainer。
    /// </summary>
    /// <typeparam name="F">转换函数类型</typeparam>
    /// <returns>包含转换后值的新 ValueContainer</returns>
    template<typename F>
    auto map(F lambda) const& {
        using ResultType = std::invoke_result_t<F, const V&>;
        if (v.has_value()) {
            return ValueContainer<ResultType>(lambda(*v));
        }
        else {
            ValueContainer<ResultType> newContainer;
            newContainer.setReason(reason);
            return newContainer;
        }
    }
    template<typename F>
    auto flatMap(F lambda)&& {
        using InnerContainerType = std::invoke_result_t<F, V&>;
        static_assert(std::is_constructible_v<InnerContainerType, InnerContainerType&&>, "Lambda for flatMap must return a movable ValueContainer.");

        if (v.has_value()) {
            return lambda(*v);
        }
        else {
            using ResultType = typename InnerContainerType::value_type;
            ValueContainer<ResultType> newContainer;
            newContainer.setReason(reason);
            return newContainer;
        }
    }
    using value_type = V;
    // flatMap 的 const 左值引用重载 (你已有的)
    template<typename F>
    auto flatMap(F lambda) const& {
        using InnerContainerType = std::invoke_result_t<F, const V&>;
        static_assert(std::is_constructible_v<InnerContainerType, InnerContainerType&&>, "Lambda for flatMap must return a movable ValueContainer.");

        if (v.has_value()) {
            return lambda(*v);
        }
        else {
            using ResultType = typename InnerContainerType::value_type;
            ValueContainer<ResultType> newContainer;
            newContainer.setReason(reason);
            return newContainer;
        }
    }
    /// <summary>
	/// 当有值时执行 lambda 函数,并返回当前对象。
    /// </summary>
    /// <typeparam name="F">lambda函数</typeparam>
    /// <param name="lambda">lambda函数</param>
    /// <returns>返回自身</returns>
    template<typename F>
    auto tap(F lambda)&& {
        if (v.has_value()) {
            lambda(*v);
        }
        return std::move(*this);
    }

    template<typename F>
    auto tap(F lambda) const& {
        if (v.has_value()) {
            lambda(*v);
        }
        return *this;
    }
    template<typename F>
    auto tap(F lambda)& {
        if (v.has_value()) {
            lambda(*v);
        }
        return *this;
    }
};

具体代码

map方法用于返回处理后的新的数据类型使用VC包裹,flatmap函数将lambda内部返回VC变量展开重新返回展开后的VC变量,tap函数用于处理数据并返回自身,其他方法由数据名即可看出作用

希望我的博客能够对你有帮助

hhhh6448

hhhh6448

转载请注明出处,欢迎留言交流~

评论

评论区还没开放,部署评论服务后就能留言啦~

主题色