使用带有“检查”功能的包装器是处理可选类型而不是传统方法的好方法吗?

问题描述 投票:0回答:1

像 C++ 和 Rust 这样的语言有一个 Option 类型,它基本上是一个带有值的枚举/布尔值。

但我觉得这可能会出现一些问题,例如:

  • 使用您的类型返回/传递额外字段的额外开销
  • 如果您决定函数应该返回可选值而不是原始值,则会破坏 ABI 兼容性。

那么为什么不将 bool 值与值放在一起,而是使用一个与类型关联的函数来检查返回的值是否有效。

例如:

template<typename T, bool(*ISOK)(T&)>
struct Errorable
{
    private:
    T val;

    public:
    Errorable(T v)
    {
        val = v;
    }
    
    bool is_ok()
    {
        return ISOK(val);
    }

    bool is_err()
    {
        return !ISOK(val);
    }

    T unwrap_or(T o)
    {
        if(ISOK(val))
            return val;
        return o;
    };

    T unwrap_forced()
    {
        return val;
    }
};

可以这样使用:

bool idx_ok(int& idx)
{
    return idx >= 0;
}

Errorable<int, idx_ok> array_idx_of(int *arr, int len, int elm)
{
    for(int i = 0 ; i < len ; i++)
    {
        if(arr[i] == elm)
        {
            Errorable<int, idx_ok> ok(i);
            return ok;
        }
    }
    Errorable<int, idx_ok> err(-1);
    return err;
}

然后

int main()
{
    int arr[5] = {1, 2, 3, 4, 5};
    auto idx = array_index_of(arr, 5, 6);
    if(idx.is_ok())
    { ... }
}

抱歉,如果我的 C++ 不好,我是一名需要模板的 C 程序员

c++ option-type
1个回答
0
投票

如果您的函数可以返回值或“无值”,那么请随意使用

std::optional
:

std::optional<int> tryToGetValue() {
  if (condition) return 100;
  else return std::nullopt;
}

如果您的函数总是返回一些值/结构,但是结构不变量并不总是满足,请返回带有验证函数的结构(您可以将其概括为提供自定义验证器,使用多态性等):

struct JsonResponse {
  bool isValid();
  int getValue(/* some args */);
  // some logic
};
JsonResponse requestReply(/* ... */);

如果您的函数应该始终返回一个值,并且如果该值无效,则继续其余的程序逻辑是没有意义的,则抛出异常:

int getElement(int idx) {
  if (container.size() <= idx) throw std::logic_error("idx out of bounds");
}

尝试始终优先考虑语义,并编写表达意图的代码。然后(仅限专家!)您可以尝试对其进行分析并优化。

© www.soinside.com 2019 - 2024. All rights reserved.