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

Convenient type-inferring way to reassign `unique_ptr` value with new object

本文关键字:新分配 ptr unique 分配 对象 类型 方法 新对象 方便      更新时间:2023-10-16

是否有一种方便的方法来重新分配具有拥有对象的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>更简洁的了。

EDIT:为支持operator=的类型重新赋值的最简洁的方法当然是使用operator=:

*foo = value;`

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

将参数(或其引用)存储到具有模板化转换操作符的代理对象中,该操作符可以推断目标类型。一旦你推导出了这个对象,就构造这个新对象。

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)...)};
}

它不是成员函数,但自由函数基本上可以实现以下功能:

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

(我认为这个解决方案并不理想)

#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>();
}

因为你有唯一的所有权,除非类型是不可复制的,你可以简单地做

*foo = value;