方便的类型推断方式,用新对象重新分配`unique_ptr`值

时间:2016-08-29 22:47:06

标签: c++ c++14 unique-ptr

是否有方便的方法使用拥有的对象重新分配unique_ptr的值,而无需重新指定类型?

例如:

std::unique_ptr<int> foo;
// .... Later, once we actually have a value to store...
foo = std::make_unique<int>(my_cool_value);

当然int并不是太过分,但foo::element_type可能很长或在重构后会发生变化。

因此,要使用类型推断,我们可以这样做:

foo = std::make_unique<decltype(foo)::element_type>(value);

...但这很可怕(foo::element_type不起作用,因为foo不能用于常量表达式。)

理想情况下,std::unique_ptr会支持转发emplace - 类似方法:

foo.reassign(value);

这将释放旧值,就像std::vector::emplace一样,就地构建新拥有的对象。

....但据我所知,没有比make_unique<decltype(foo)::element_type>更简洁的了。

编辑:为支持operator=的类型重新分配值的最简洁方法当然是使用operator=

*foo = value;`

...但我不想依赖element_type的可复制性(例如,我在尝试使用输入文件流时最初遇到此问题)。

4 个答案:

答案 0 :(得分:2)

使用模板化转换运算符将参数(或对其的引用)存储到代理对象中,该运算符推导出目标类型。然后在推导出新对象后构造它。

template<class... Args>
struct maker {
    template<class T>
    operator std::unique_ptr<T>() && {
        return make<T>(std::index_sequence_for<Args...>());
    }
    std::tuple<Args...> args;
private:  
    template<class T, size_t ... Is>
    std::unique_ptr<T> make(std::index_sequence<Is...>) {
        return std::make_unique<T>(std::get<Is>(std::move(args))...);
    }

};

template<class... Args>
auto maybe_make_unique_eventually(Args&&... args){
    return maker<Args&&...>{std::forward_as_tuple(std::forward<Args>(args)...)};
}

答案 1 :(得分:1)

它不会成为会员功能,但免费功能基本上可以达到这个目的:

template<typename T, typename D, typename...Args>
void TakeNew(std::unique_ptr<T,D>& up, Args&&... args)
{
  up.reset(new T{std::forward<Args>(args)...});
  // or use parentheses for consistency with `make_unique`; see comments
}

// usage...
auto foo = std::make_unique<int>(3);
// .... Later...
TakeNew(foo, 5);

(我不认为这个解决方案是理想的。)

答案 2 :(得分:1)

#include <memory>


// a class with a long and unweildy name
namespace mary {
  namespace poppins {
    struct supercalafragalisticexpialadocious
    {
    };
  }
}


int main()
{
  // what we don't want to have to do:

  auto a = std::make_unique<mary::poppins::supercalafragalisticexpialadocious>();

  // so alias the typename

  using atrocious = mary::poppins::supercalafragalisticexpialadocious;

  // same type with a shorter name
  a = std::make_unique<atrocious>();
}

答案 3 :(得分:0)

由于您拥有独特的所有权,除非该类型不可复制,否则您可以执行

SELECT
    od.orderID, SUM(pod.qty) as Totalqty, SUM(od.qty) as od_qty
FROM
    PurchaseOrderDetails pod
INNER JOIN 
    OrderDetails od ON od.orderID = pod.orderID AND pod.orderID = 15506
GROUP BY
    od.orderID