从shared_ptr中推导出weak_ptr参数

3
以下内容让我遇到了编译错误:

无法推断出“const std::weak_ptr<_Ty> &”的模板参数 来自“std::shared_ptr”

#include <memory>

class Foo
{
public:

    template<typename R>
    void Bar(std::weak_ptr<R> const & p)
    {
        p;
    }
};

int main(void)
{
    auto foo = Foo();
    auto integer = std::make_shared<int>();

    foo.Bar(integer);
}

我尝试过,
template<typename R>
void Bar(std::weak_ptr<R::element_type> const & p)
{

}

这段代码似乎在语法上不正确。下面的代码可以工作,但我想知道是否可能在p标签中进行转换,而不需要创建另一个临时变量?

template<typename R>
void Bar(R const & p)
{
    auto w = std::weak_ptr<R::element_type>(p);
}

要明确的是,我希望明确说明函数应该接受一个shared_ptr或weak_ptr,因此我不喜欢R const & p的解决方案。
当然,为了完整性,这也可以工作:
template<typename R>
void Bar(std::shared_ptr<R> const & p)
{
    auto w = std::weak_ptr<R>(p);
}

element_type是shared_ptr(特征)的类型。在这种情况下,<R>是一个shared_ptr<R:element_type>。至少这似乎是类型推断过程告诉我的。因此,在示例中,element_type将是“int”。 - Robinson
4个回答

3

std::weak<A>的模板参数R无法从std::shared_ptr<A>的实例中推导出来,因为它的转换构造函数(接受std::shared_ptr<Y>)是一个构造函数模板,这意味着Y可以是任何类型——而且没有办法从Y(被推导为A)推导出R。请查看转换构造函数。

你可以这样写:

template<typename T>
auto make_weak(std::shared_ptr<T> s) ->  std::weak_ptr<T>
{
  return { s };
}

然后按照以下方式调用:
foo.Bar( make_weak(integer) );

2
使用 C++ 17 的 类模板推导,现在应该是合法的:
auto shared = std::make_shared< int >( 3 );
auto weak = std::weak_ptr( shared );
std::weak_ptr weak2( shared );

coliru上查看。

2
顺便提一下,这个问题在clang的libcxx中直到2020年5月才得到修复。 - Jan Kundrát

1
因为您比编译器更聪明,所以必须帮助它推断出类型。
观察您代码的这部分。
template<typename R>
void Bar(std::weak_ptr<R> const & p)

你知道对于可能存在的每个R,都有恰好一个R存在,其中有从std::shared_ptr<int>进行的隐式转换。你可能没有在其他地方编写适用于此处的转换运算符。
你的C++编译器不会知道或假设这一点。因此,你应该这样调用函数:
foo.Bar( std::weak_ptr<int>{integer} );

或者尝试Mark B答案中的方法。


1
你需要处理两种(语言上)完全无关的类型,因此你需要提供两个重载函数,一个针对每种指针类型。shared_ptr版本可以通过在其调用中提供正确的T来调用weak_ptr版本。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接