当函数 return 类型为 bool 时,为什么我不能 return C++14 中的共享指针?

Why can't I return a shared pointer in C++14 when the function return type is bool?

我正在使用 g++ 并编写了一个简单的函数:

#include <memory>

std::shared_ptr<char> ptr;

bool fails_compiling()
{
    return ptr;
}

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

    return static_cast<bool>(ptr);

现在可以编译了。

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

如果你查看 std::shared_ptr 的 bool 转换运算符,你会看到它被声明为:

explicit operator bool() const;

explicit 的使用只是告诉编译器禁止 implicit conversion, which is what would have taken place because the return type of your function is different from the object type you are returning. However, this doesn't affect contextual conversions.

发生在任何上下文中:

  • controlling expression of if, while, for;
  • the logical operators !, && and ||;
  • the conditional operator ?:;
  • static_assert;
  • noexcept.

以上引用自 cppreference

Why would the return algorithm not attempt an auto-conversion to bool like the if() and while() do?

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

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

In the following five contexts, the type bool is expected and the implicit conversion sequence is built if the declaration bool t(e); is well-formed. that is, the explicit user-defined conversion function such as explicit T::operator bool() const; is considered. Such expression e is said to be contextually convertible to bool.

  • controlling expression of if, while, for;
  • the logical operators !, && and ||;
  • the conditional operator ?:;
  • static_assert;
  • noexcept.

为什么代码无法编译。

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

  • 用作内置布尔运算符 &&||! 或其等价物 and、[=34] 的参数=] 和 not.

值得注意的是,尽管 explicit,这些允许隐式转换为 bool 的异常,称为 上下文转换 ,不包括 return 语句表达式.


在其他情况下是否也可以忽略 explicit

在其他什么情况下,可以忽略转换运算符上的 explicit

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

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

Certain language constructs require conversion to a value having one of a specified set of types appropriate to the construct. An expression e of class type E appearing in such a context is said to be contextually implicitly converted to a specified type T and is well-formed if and only if e can be implicitly converted to a type T that is determined as follows: E is searched for conversion functions whose return type is cv T or reference to cv T such that T is allowed by the context. There shall be exactly one such T.

例如,

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

If of class type, the operand [of delete] is contextually implicitly converted (Clause 4) to a pointer to object type.

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

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

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