从 int 到 shared_ptr 的隐式转换
Implicit conversion from int to shared_ptr
考虑以下代码:
#include <iostream>
#include <memory>
void f(std::shared_ptr<int> sp) {}
template <typename FuncType, typename PtrType>
auto call_f(FuncType f, PtrType p) -> decltype(f(p))
{
return f(p);
}
int main()
{
f(0); // doesn't work for any other int != 0, thanks @Rupesh
// call_f(f, 0); // error, cannot convert int to shared_ptr
}
在 main()
的第一行中,整数 0
被转换为 std::shared_ptr<int>
并且调用 f(0)
成功,没有任何问题。但是,使用模板调用函数会使情况有所不同。第二行将不再编译,错误为
error: could not convert 'p' from 'int' to 'std::shared_ptr<int>'
我的问题是:
- 为什么第一次调用成功,第二次不成功?我在这里遗漏了什么吗?
- 我也不明白从
int
到 std::shared_ptr
的转换是如何在调用 f(0)
中执行的,因为它看起来 std::shared_ptr
只有明确的构造函数。
PS:此示例的变体出现在 Scott Meyers 的 Effective Modern C++ 项目 8 中,作为使用 nullptr
保护此类调用的一种方式.
根据 [conv.ptr]/1(此处引用 N4296):
A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t
. ... A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t
.
shared_ptr
有一个非显式构造函数,它接受 std::nullptr_t
每个 [util.smartptr.shared.const]/1:
constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }
构造一个空的、非拥有的shared_ptr
。
当你直接调用f(0)
时,0
是一个空指针常量,被上面的构造函数隐式转换为shared_ptr<int>
。当您改为调用 call_f(f, 0)
时,文字 0 的类型被推断为 int
,当然 int
不能转换为 shared_ptr<int>
.
std::shared_ptr 有一个采用 std::nullptr_t 的构造函数,文字 0
是一个可转换为 std::nullptr_t 来自草案 C++ 标准部分 4.10
[conv.ptr] (强调我的前进):
A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type
std::nullptr_t. A null pointer constant can be converted to a
pointer type; the result is the null pointer value of that type and is
distinguishable from every other value of object pointer or function
pointer type. Such a conversion is called a null pointer conversion.
Two null pointer values of the same type shall compare equal. The
conversion of a null pointer constant to a pointer to cv-qualified
type is a single conversion, and not the sequence of a pointer
conversion followed by a qualification conversion (4.4). A null
pointer constant of integral type can be converted to a prvalue of
type std::nullptr_t. [ Note: The resulting prvalue is not a null
pointer value. —end note ]
在你的第二种情况下 p
被推断为 int 类型,它虽然值为零,但不再是空指针常量,因此不适合案例.
如T.C。指出用 DR 903 改变了措辞,它需要一个值为零的整数文字,而不是 整数常量表达式 其计算结果为零:
A null pointer constant is an integer literal (2.14.2) with value
zero or a prvalue of type std::nullptr_t. A null pointer constant
can be converted to a pointer type; the result is the null pointer
value of that type and is distinguishable from every other value of
object pointer or function pointer type.
第一次调用 f(0) 被编译为 f(nullptr),这对编译器来说很好(但我认为不应该)。第二次调用将为函数创建声明以处理任何 int,这是非法的。
有趣的是,即使这段代码也有效:
f(3-3);
f(3*0);
考虑以下代码:
#include <iostream>
#include <memory>
void f(std::shared_ptr<int> sp) {}
template <typename FuncType, typename PtrType>
auto call_f(FuncType f, PtrType p) -> decltype(f(p))
{
return f(p);
}
int main()
{
f(0); // doesn't work for any other int != 0, thanks @Rupesh
// call_f(f, 0); // error, cannot convert int to shared_ptr
}
在 main()
的第一行中,整数 0
被转换为 std::shared_ptr<int>
并且调用 f(0)
成功,没有任何问题。但是,使用模板调用函数会使情况有所不同。第二行将不再编译,错误为
error: could not convert 'p' from 'int' to 'std::shared_ptr<int>'
我的问题是:
- 为什么第一次调用成功,第二次不成功?我在这里遗漏了什么吗?
- 我也不明白从
int
到std::shared_ptr
的转换是如何在调用f(0)
中执行的,因为它看起来std::shared_ptr
只有明确的构造函数。
PS:此示例的变体出现在 Scott Meyers 的 Effective Modern C++ 项目 8 中,作为使用 nullptr
保护此类调用的一种方式.
根据 [conv.ptr]/1(此处引用 N4296):
A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type
std::nullptr_t
. ... A null pointer constant of integral type can be converted to a prvalue of typestd::nullptr_t
.
shared_ptr
有一个非显式构造函数,它接受 std::nullptr_t
每个 [util.smartptr.shared.const]/1:
constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }
构造一个空的、非拥有的shared_ptr
。
当你直接调用f(0)
时,0
是一个空指针常量,被上面的构造函数隐式转换为shared_ptr<int>
。当您改为调用 call_f(f, 0)
时,文字 0 的类型被推断为 int
,当然 int
不能转换为 shared_ptr<int>
.
std::shared_ptr 有一个采用 std::nullptr_t 的构造函数,文字 0
是一个可转换为 std::nullptr_t 来自草案 C++ 标准部分 4.10
[conv.ptr] (强调我的前进):
A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a null pointer value. —end note ]
在你的第二种情况下 p
被推断为 int 类型,它虽然值为零,但不再是空指针常量,因此不适合案例.
如T.C。指出用 DR 903 改变了措辞,它需要一个值为零的整数文字,而不是 整数常量表达式 其计算结果为零:
A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type.
第一次调用 f(0) 被编译为 f(nullptr),这对编译器来说很好(但我认为不应该)。第二次调用将为函数创建声明以处理任何 int,这是非法的。
有趣的是,即使这段代码也有效:
f(3-3);
f(3*0);