C++ 我想完善前向变量参数,除了特定类型

C++ 我想完善前向变量参数,除了特定类型,c++,shared-ptr,smart-pointers,c++14,perfect-forwarding,C++,Shared Ptr,Smart Pointers,C++14,Perfect Forwarding,我有以下几点 #include <iostream> #include <memory> template<typename _type> class handle { using ptr = std::shared_ptr<_type>; using pptr = std::shared_ptr<ptr>; public: handle(handle<_type> const & other) :

我有以下几点

#include <iostream>
#include <memory>

template<typename _type>
class handle
{
  using ptr = std::shared_ptr<_type>;
  using pptr = std::shared_ptr<ptr>;
public:
  handle(handle<_type> const & other) :
    mData(make_pptr(*(other.mData)))
  {}


  handle(_type && data) :
    mData(make_pptr(std::move(data)))
  {}
private:
  pptr mData;

  template<typename ..._args>
  constexpr auto make_ptr(_args && ...args)
  {
    return std::make_shared<_type>(std::forward<_args>(args)...);
  }

  constexpr auto make_pptr(ptr const & pointer)
  {
    return std::make_shared<ptr>(pointer);
  }

  template<typename ..._args>
  constexpr auto make_pptr(_args && ...args)
  {
    return std::make_shared<ptr>(make_ptr(std::forward<_args>(args)...));
  }
};

int main()
{
  handle<int> h = 5;
  handle<int> h2(h);
}
不编译。问题函数都是

make_pptr
据我所知,模板函数总是被选择的,因为编译器试图找到最专门的函数调用,而完美的转发恰恰创建了这一点

我发现下面两页似乎处理了类型trait
std::enable_if
std::is_same
的问题

实际问题是,如何更改此函数,以便在向工厂函数传递已有指针时调用非模板函数

打电话时有没有常用的方法

handle<int> h2(h);
这是完全匹配的

您可以使用

handle(handle<_type> const & other) :
    mData(make_pptr(static_cast<const ptr&>(*(other.mData))))
{}
句柄(句柄常量和其他):
mData(make_pptr(static_cast(*(other.mData)))
{}
来解决你的问题

或者添加重载以供简单参考。

正如Jarod所解释的,在构造函数中

handle(handle<_type> const & other) :
  mData(make_pptr(*(other.mData)))
{}
constexpr auto make_pptr(ptr & pointer)
{
  return std::make_shared<ptr>(pointer);
}
另一种选择是约束完美转发重载,以便仅当参数包的第一个参数不是
共享的\u ptr
时,它才可行

一些帮助程序用于评估参数包中的第一种类型是否为
共享\u ptr


我还必须更改您的
make_ptr
重载,因为您在示例中定义它的方式要求
\u type
可以从
nullptr
构造

constexpr auto make_ptr()
{
  return std::make_shared<_type>();
  // no nullptr arg above, shared_ptr default ctor will initialize _type* to nullptr
}
constexpr自动生成
{
返回std::make_shared();
//上面没有nullptr arg,共享\u ptr默认构造函数将_type*初始化为nullptr
}

什么是
T
?你在模板类中吗?到底是什么工作方式不符合你的要求?偏序应确保在传递左值/右值
共享\u ptr
时选择正确的函数模板。你能发布一个不起作用的例子吗?@Lightness Races in Orbit:你能说明这个问题的问题是什么吗?@Jarod42:是的,这是一个带有这些函数的模板类,我更新了这个问题。@Praetorian:模板函数总是被调用,即使我传递了一个共享的ptr,我添加的两篇文章正好涵盖了这个主题,但一篇是关于完美的转发构造函数的,另一篇,我不知道为什么对我不起作用。我知道这一点,但是在
make\u pptr
函数中没有其他方法来做决定吗?因为我想这会更干净,这也是我在编写重载时的意图。@satanik:你可以使用Praetorian所示的SFINAE,但我不确定它比非常量左值重载的解决方案更干净。这实际上解决了我的问题,但还有一个小问题。当我在没有参数的情况下调用函数时,它不会编译。当我在逻辑
| |
操作符之后移除零件时,它工作正常。所以我想问题是,逻辑运算符对这两部分都进行求值,即使第一部分成功。我认为通常情况并非如此。我在你的代码@satanik中测试过对不起,那是我的错。即使未计算第二部分,整个表达式也必须有效,这就是为什么参数包为空时它不会编译。我添加了一个额外的间接级别,这样当包为空时,您就不会去查询包中的第一个类型。它就像一个符咒,但是您能解释一下结构
是共享的\u ptr
会发生什么吗?我想我不能完全理解
zeroth_type
提取类型列表的第一种类型<代码>是共享的\u ptr似乎使
是相同的
比较,但两者都继承自
false\u类型
true\u类型
,为什么要使用
false\u类型
?而
大小是多少?@satanik当
eval\u args
false
,即
sizeof…(\u args)==0时,主
是共享的\u ptr
模板匹配。在这种情况下,我们知道(空)参数包中的第一个类型不是
shared\u ptr
,因此我们从
false\u-type
继承。
的部分专门化是共享的\u ptr
sizeof…(\u args)时匹配=0
,然后我们从
true\u-type
false\u-type
继承,这取决于包中的第一个类型是否是
共享的\u-ptr
+1以使用
而不是
。但是我已经做了两个完美的转发功能,一个带有
arg&&…
和一个带有
arg&&
,并且只在
arg
情况下测试共享ptr。一个类
X
作为一个ctor
(shared\u ptr,int)
将被上述代码阻止,不是吗?在我的例子中,只有
X(shared_ptr)
被阻止。一个更强大的解决方案还可以解决在存储
共享ptr
时,您可能会被传递一个
共享ptr
handle(handle<_type> const & other) :
  mData(make_pptr(*(other.mData)))
{}
constexpr auto make_pptr(ptr & pointer)
{
  return std::make_shared<ptr>(pointer);
}
namespace detail
{
    template<typename... _args>
    using zeroth_type = typename std::tuple_element<0, std::tuple<_args...>>::type;

    template<typename T, bool eval_args, typename... _args>
    struct is_shared_ptr
    : std::false_type
    {};

    template<typename T, typename... _args>
    struct is_shared_ptr<T, true, _args...>
    : std::is_same<std::decay_t<zeroth_type<_args...>>,
                   std::shared_ptr<T>
                  >
    {};
}
template<typename ..._args,
         typename = std::enable_if_t<
                        not detail::is_shared_ptr<_type, sizeof...(_args), _args...>::value
                    >
        >
constexpr auto make_pptr(_args && ...args)
{
  return std::make_shared<ptr>(make_ptr(std::forward<_args>(args)...));
}
constexpr auto make_ptr()
{
  return std::make_shared<_type>();
  // no nullptr arg above, shared_ptr default ctor will initialize _type* to nullptr
}