Implicit conversion from int to shared_ptr

社会主义新天地 提交于 2019-12-19 07:05:44

问题


Consider the code below:

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

In the first line in main(), the integer 0 is converted to a std::shared_ptr<int> and the call f(0) succeeds without any problem. However, using a template to call the function make things different. Second line will not compile anymore, the error being

error: could not convert 'p' from 'int' to 'std::shared_ptr<int>'

My questions are:

  1. Why does the first call succeed and the second doesn't? Is there anything I'm missing here?
  2. I don't understand also how the conversion from int to std::shared_ptr is being performed in the call f(0), as it looks like std::shared_ptr has only explicit constructors.

PS: A variant of this example appears in Scott Meyers' Effective Modern C++ Item 8, as a way of protecting such calls with nullptr.


回答1:


std::shared_ptr has a constructor that takes std::nullptr_t, literal 0 is a null pointer constant that is convertiable to std::nullptr_t from the draft C++ standard section 4.10 [conv.ptr] (emphasis mine going forward):

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 ]

in your second case p is being deduced as type int which although has the value zero is no longer a null pointer constant and so does not fit the same case.

As T.C. points out the wording was changed with DR 903 which requires an integer literal with value zero as opposed to an integral constant expression which evaluates to zero:

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.




回答2:


Per [conv.ptr]/1 (quoting N4296 here):

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 has a non-explicit constructor that accepts std::nullptr_t per [util.smartptr.shared.const]/1:

constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }

which constructs an empty, non-owning shared_ptr.

When you call f(0) directly, 0 is a null pointer constant that is implicitly converted to shared_ptr<int> by the above constructor. When you instead call call_f(f, 0), the type of the literal 0 is deduced to int and of course an int cannot be converted to a shared_ptr<int>.




回答3:


The firs call f(0) is compiled as f(nullptr), which is fine for the compiler (but it should not be in my opinion). The second call will create declaration for a function to work on any int, which is illegal.

Funny thing is, that even this code works:

f(3-3);
f(3*0); 


来源:https://stackoverflow.com/questions/28588827/implicit-conversion-from-int-to-shared-ptr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!