【问题标题】:how does std::optional work under the hood?std::optional 如何在幕后工作?
【发布时间】:2023-04-03 01:05:02
【问题描述】:

我刚刚了解了 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 我不是 100% 确定你想说什么……但你有什么建议?
  • 嗯,实际上有两个问题。一个是关于使用{} 代替optional 对象,一个是关于一个类似于bool 的可选对象。很难找到包含这两个问题的特定标题。每一个都非常简单(“如何让我的类使用 {} 代替对象?”、“如何让我的类表现得像一个布尔值?”)
  • return {} 这里说“返回std::optional&lt;std::string&gt; 的实例,使用默认构造函数初始化”。这是return std::optional&lt;std::string&gt;(); 的简写。此语法并非特定于 std::optional。碰巧std::optional 的默认构造函数将对象设置为空状态。
  • if(name) 这里等同于if (name.operator bool()) - 它调用std::optional 提供的a conversion operator。该操作符与has_value() 做同样的事情

标签: c++ c++-standard-library stdoptional


【解决方案1】:
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;
}

非常简化,缺少赋值运算符等等。

【讨论】:

  • 这个例子和实际的std::optional 实现之间的最大区别是你的实例构造了一个T 的实例,即使它被认为没有值。真正的std::optional 不会。
  • std::optional 使用explicit operator bool。转换是显式的,而不是隐式的。
【解决方案2】:

我如何创建自己的类以使 return {} 有效?

通过使类默认可构造。具体怎么做取决于班级。在类是隐式默认可构造的情况下,您无需执行任何操作,而在其他情况下,您可能需要显式声明构造函数。例如:ClassName() = default;

变量名如何返回布尔值

想想这个变量名如何“返回一个布尔值”:

int x = 42;
if (x)
    ;

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

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

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

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

通过提供转换运算符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-18
    • 2011-02-17
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多