从int到shared_ptr的隐式转换

时间:2015-02-18 16:37:42

标签: c++ c++11 type-conversion shared-ptr implicit-conversion

请考虑以下代码:

#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>'

我的问题是:

  1. 为什么第一次通话成功而第二次通话不成功?我在这里找不到任何东西?
  2. 我也不太了解在int调用中如何执行从std::shared_ptrf(0)的转换,因为它看起来只有std::shared_ptr构造函数。
  3. PS:这个例子的一个变体出现在Scott Meyers&#39; 有效的现代C ++ 第8项,作为使用nullptr保护此类来电的一种方式。

3 个答案:

答案 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);