【问题标题】:Why can't I return a shared pointer in C++14 when the function return type is bool?当函数返回类型为 bool 时,为什么我不能在 C++14 中返回共享指针?
【发布时间】:2017-01-26 14:22:23
【问题描述】:

我在用g++,写一个简单的函数:

#include <memory>

std::shared_ptr<char> ptr;

bool fails_compiling()
{
    return ptr;
}

从我在界面中看到的,shared_ptr 实现包括一个 bool 运算符,我什至可以应用这样的快速修复:

    return static_cast<bool>(ptr);

现在可以编译了。

为什么返回算法不会像if()while() 那样尝试自动转换为bool

【问题讨论】:

  • 布尔运算符是explicit
  • 那个布尔运算符是为了向后兼容糟糕的风格。更好地比较与 nullptr 的不等式,这需要与转换为 bool 的 return ptr != nullptr; 相等。
  • @ÖöTiib,在哪个官方文档中说这是“向后兼容”?
  • 为什么要把明显的真理写进文档? ptr 很有用,因为 ptr != nullptr 显然是从 C 继承的。shared_ptr::operator boolexplicit 显然是为了将其用法缩小到有限的上下文中。 B. Stroustrup 无数次提到类型安全作为意图。

标签: c++ return return-value smart-pointers boolean-expression


【解决方案1】:

为什么代码无法编译。

std::shared_ptr 的转换为bool 运算符声明为explicit,因此通常不会为隐式转换调用。

特别是它不会在return 语句的上下文中被调用。

并且不会考虑选择函数重载,即foo(p) 不会解析为采用bool 参数的foo 重载。

然而,有很多方法可以显式表达转换,包括:

!!ptr

ptr != nullptr

ptr.get() != nullptr

static_cast<bool>( ptr )

ptr.operator bool()

隐式转换为bool的一般情况。

在某些情况下,operator bool() 上的explicit忽略,以便使事情主要像在 C++03 中一样工作。也就是说,为了使事情与在 C++11 中的转换运算符上允许使用 explicit 之前所采用的方案一样工作。这些例外是

  • ifwhilefor 中用作(语法产生)条件,但不在switch 中,

  • :? 选项、static_assertnoexcept 中用作条件,

  • 用作内置布尔运算符&amp;&amp;||! 或它们的等价物andornot 的参数。

同样值得注意的是,这些允许隐式转换为bool 的异常(称为上下文转换)不包括return 语句表达式。


explicit 在其他情况下也可以忽略吗?

在其他哪些情况下(如果有)可以忽略转换运算符上的explicit

嗯,没有。但是非explicit转换运算符,即隐式转换运算符,可以在上下文未指定要转换的确切类型的情况下隐式调用。

C++11 §4/5(转换):

某些语言结构需要转换为具有适当的指定类型集合之一的值 到构造。出现在这种上下文中的类类型 E 的表达式 e 被称为在上下文中隐式转换 为指定类型 T,并且如果并且仅当 e 可以隐式转换为 一个类型 T 确定如下:E 搜索返回类型为 cv T 或引用 cv T 的转换函数,这样T 是上下文允许的。应该有一个这样的T

例如,

C++11 §5.3.5/1(expr.delete):

如果是类类型,则操作数 [delete] 是上下文相关的 隐式转换(第 4 条)为指向对象类型的指针。

…所以,对我来说有点反直觉!,以下应该使用符合标准的编译器进行编译:

struct Foo
{
    operator int*() const { return nullptr; }
};

auto main()
    -> int
{
    delete Foo();
}

【讨论】:

    【解决方案2】:

    为什么返回算法不会像if()while() 那样尝试自动转换为bool

    std::shared_ptr::operator boolexplicit的转换函数,所以不允许隐式转换,但static_cast(显式转换)效果很好。

    当用于ifwhile时,contextual conversions生效,则考虑显式用户自定义转换函数。在这种情况下,std::shared_ptr在上下文中转换为bool

    在以下五个上下文中,类型 bool 是预期的,并且如果声明 bool t(e); 格式正确,则会构建隐式转换序列。即考虑explicit T::operator bool() const;等显式用户定义的转换函数。这样的表达式 e 被称为 在上下文中可转换为 bool

    • 控制 if、while、for 的表达式;
    • 逻辑运算符 !、&& 和 ||;
    • 条件运算符 ?:;
    • static_assert;
    • 没有例外。

    【讨论】:

      【解决方案3】:

      如果您检查std::shared_ptr 的布尔转换运算符,您会看到它被声明为:

      explicit operator bool() const;
      

      使用explicit 只是告诉编译器禁止implicit conversion,因为函数的返回类型与返回的对象类型不同,所以会发生这种情况。但是,这不会影响contextual conversions

      发生在任何上下文中:

      • 控制ifwhilefor的表达式;
      • 逻辑运算符!&amp;&amp;||
      • 条件运算符?:;
      • static_assert;
      • noexcept

      以上引用自 cppreference

      【讨论】:

      • 也就是说,他们有一些bool 类型的特殊情况,其中不包括return 语句。
      • 是的,类似的。我会说explicitexplicit 的意义上没有完全 受到尊重的唯一地方是bool 转换运算符。正如你所看到的,它只适用于非常具体和有限的上下文,这是有道理的....
      猜你喜欢
      • 2012-10-03
      • 1970-01-01
      • 2021-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-13
      • 2021-12-15
      相关资源
      最近更新 更多