std::optional在内部是如何工作的?

3

我刚学习了一些C++17的有用特性,其中包括std::optional功能...

但是我对于std::optional还有一些不理解的地方,希望有人能够解释一下:

首先,据我所知,在std::optional中返回值既可以是指定的类型,也可以什么都没有,就像这样:

std::optional<std::string> getName()
{
    if(person.hasName())
    {
        return person.name;
    }
    else 
    {
        return {};
    }
}

return {} 如何返回空值?举个例子,如果我要创建一个类,返回指定的值或者空值,我该如何编写类使得return {}是有效的呢?我是否有误解?

我的第二个问题是当你想要检查返回值时,可以使用以下两种方式:

int main()
{
    std::optional<std::string> name = getName();
    if(name.has_value())  // check if the name is valid using the has_value function
    {
        ...
    }
}

或者我也可以做以下事情:


int main()
{
    std::optional<std::string> name = getName();
    if(name)  // check if the name is valid only using the variable name ???
    {
        ...
    }
}

我真的很困惑,变量名怎么可能返回一个布尔值?不像对象的构造函数可以返回任何东西,所以这怎么可能呢?

再说,假设我想创建一个类,它与std::optional有点相似,如何使我的类的实例可以用作布尔值?

我真的很感激那些回答我的问题而非关于何时使用std::optional或为什么不应该创建执行相同操作的类等的回答。

谢谢!


你的标题有点误导人,这些是影响API的语言特性,而不是任何底层的东西。就目前而言,标题让人觉得你会问类似于如何构建和销毁以在已连接和未连接之间切换的问题。 - chris
@chris 我不能百分之百确定你想说什么... 但你有什么建议吗? - Ronald joe
实际上,这里有两个问题。一个是关于在可选对象的位置使用 {},另一个是关于可选对象像 bool 一样运作。很难找到一个特定的标题来涵盖这两个问题。每个问题都很简单明了(“如何使我的类能够在对象的位置使用 {}?”,“如何使我的类像 bool 一样运作?”)。 - chris
2
这里的 return {} 表示“返回一个使用默认构造函数初始化的 std::optional<std::string> 实例”。它是 return std::optional<std::string>(); 的简写形式。这种语法不仅适用于 std::optional,而且恰好 std::optional 的默认构造函数将对象设置为空状态。 - Igor Tandetnik
1
if(name) here is equivalent to if (name.operator bool()) - it calls a conversion operator that std::optional provides. This operator does the same thing as has_value() - Igor Tandetnik
这些答案没有回答我想要的,但是这个链接很有帮助:https://dev59.com/c2Qn5IYBdhLWcg3wZGd4 - Andrew
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
0
return {};

将简单地调用类的默认构造函数。

通过为类提供一个转换运算符到bool,它可以在需要时隐式转换为bool。

它看起来会像这样:

template <typename T>
class optional {
    public:
    optional() {}
    optional(T t) : has_value(true), value(std::move(t)) {}

    operator bool() {
        return has_value;
    }
    
    private:
    bool has_value = false;
    T value;
}
非常简化,缺少赋值运算符等。

1
这个例子和实际的 std::optional 实现之间最大的区别在于,即使它没有值,您的实现仍会构造一个 T 的实例。而真正的 std::optional 不会这样做。 - Igor Tandetnik
1
std::optional 使用 explicit operator bool。这种转换是显式的,而不是隐式的。 - Konrad Rudolph

0
如何创建自己的类,使得返回 {} 是有效的? 通过使类默认可构造。如何实现取决于类的具体情况。在类隐式默认可构造的情况下,您无需进行任何操作,而在其他情况下,您可能需要显式声明构造函数。例如:ClassName() = default;。 变量名如何返回布尔值? 思考一下这个变量名如何“返回布尔值”:
int x = 42;
if (x)
    ;

或者这个变量名如何“返回std::string_view”:

const char* str = "example";
std::string__view sv = str;

这被称为从一种类型到另一种类型的转换。这就是在if(name)中发生的事情。

我该如何使我的类的实例可以用作布尔值?

通过提供一个转换运算符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,