请考虑以下代码:
#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
构造函数。 nullptr
保护此类来电的一种方式。
答案 0 :(得分:5)
std::shared_ptr有一个构造函数,它接受 std :: nullptr_t ,文字0
是一个空指针常量,可以转换为 std :: nullptr_t 来自草案C ++标准部分4.10
[conv.ptr] (强调我的前进):
空指针常量是整数类型的整数常量表达式(5.19)prvalue,其计算结果为零或类型的prvalue 的std :: nullptr_t 即可。空指针常量可以转换为 指针类型;结果是该类型的空指针值,并且是 可以与对象指针或函数的每个其他值区分开来 指针类型。这种转换称为空指针转换。 相同类型的两个空指针值应相等。该 将空指针常量转换为指向cv-qualified的指针 type是单个转换,而不是指针的序列 转换后进行资格转换(4.4)。 空 整数类型的指针常量可以转换为prvalue 输入std :: nullptr_t 。 [注意:生成的prvalue不是null 指针值。 - 后注]
在你的第二种情况下p
被推断为类型 int ,虽然它的值为零但不再是空指针常量,因此不适合相同的情况。
作为T.C.指出措辞是用DR 903改变的,这需要一个值为零的整数文字,而不是整数常量表达式,它的计算结果为零:
空指针常量是带有值的整数文字(2.14.2) 零或类型为std :: nullptr_t的prvalue。空指针常量 可以转换为指针类型;结果是空指针 该类型的值,可以与其他每个值区分开来 对象指针或函数指针类型。
答案 1 :(得分:2)
Per [conv.ptr] / 1(在此引用N4296):
空指针常量是一个整数文字(2.13.2),其值为零或prvalue类型为
std::nullptr_t
。 ...整数类型的空指针常量可以转换为std::nullptr_t
类型的prvalue。
shared_ptr
有一个非显式构造函数,每[util.smartptr.shared.const] / 1接受std::nullptr_t
:
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>
。
答案 2 :(得分:1)
第一次调用f(0)被编译为f(nullptr),这对编译器来说很好(但不应该在我看来)。第二个调用将为函数创建声明,以处理任何int,这是非法的。
有趣的是,即使这段代码也有效:
f(3-3);
f(3*0);