首页 > 解决方案 > 设计自己的结果/要么:成功类型和错误类型是否应该始终是明确的?

问题描述

我有一个Result/Either用于 c++ 的实现。该类具有以下类型转换构造函数

template <typename V, typename E>
class Result {
...
    template<typename X>
    constexpr Result(X&& value);
...
};

这样做的目的是启用如下代码:

Result<SomeType, int> value = SomeType{...};
EXPECT_TRUE(result.isOk());   // TRUE

// Also
Result<SomeType, int> value = 10;
EXPECT_TRUE(result.isError());   // TRUE

这对于函数返回值很重要:

Result<SuccessType, int> func() {
  SuccessType result{...};
...
  return result;
}
...

EXPECT_TRUE(func().isOk());

现在事实证明,这样的构造函数过于宽松并导致不希望的类型转换。我想限制它。

所以问题是: - 你认为允许相同类型的值结果和错误有用吗?例如: Result<MyTypeA, MyTypeA> r{};你有没有错误类型和成功类型相同并且有用的例子?

这个问题的动机是我可以摆脱 template<> 构造函数,但前提是 V 和 E 不是相同的类型:

template<class V, class E>
struct Result {
    constexpr result(V&& value);    
    constexpr result(E&& value);
...

标签: c++templatesc++17rvalue-reference

解决方案


如果您是对称的,您想隐式地从任一类型转换。如果您通过了可以转换为两者的东西,那么您希望失败。

如果您也是不对称的,就像结果一样,您希望从喜欢的类型隐式转换。从不受欢迎的类型中,您只想显式转换。

template<class X>
struct Error {
  X x;
};

template<class V, class E>
struct Result {
  Result( V&& v );
  Result( Error<E> e );
  // or even:
  template<class O,
    std::enable_if_t< std::is_convertible_v<O, E>, bool > = true
  >
  Result( Error<O> e );
};

使用看起来像:

Result<SomeType, int> value = SomeType{...};
EXPECT_TRUE(result.isOk());   // TRUE

// Also
Result<SomeType, int> value = Error{10};
EXPECT_TRUE(result.isError());   // TRUE

和:

Result<SuccessType, int> func() {
  SuccessType result{...};
...
  return result;
} 

有效,如下所示:

Result<SuccessType, int> func() {
  return Error{10};
} 

应避免隐式转换为错误状态,因为它太容易意外访问。


推荐阅读