c++ - 带有转发的延迟初始化

标签 c++ c++11 perfect-forwarding

采用可能具有以下接口(interface)的“惰性”构造函数:

template<class T>
struct LazyConstruct {
   // accept any number of arguments, 
   // which would later be used to construct T
   template<class... U>
   LazyConstruct(U&&... u) {
       // store the arguments somehow
   }
   T& get() {
      if(!data) data.reset( new T( /* unpack the arguments */ ) );
      return *data;
   }
private:
   std::unique_ptr<T> data;
};

什么是实现它的好方法?

最佳答案

这里有一些复杂的方法来做你想做的事。基本思想是让 LazyConstruct 将参数包存储在一个 tuple 中,然后根据需要解压 tuple 以构造 T.

template<class T, class... Args>
struct LazyConstruct {
   // accept any number of arguments, 
   // which would later be used to construct T
   template<class... U>
   LazyConstruct(U&&... u)
   : args(std::make_tuple(std::forward<U>(u)...))
   {
   }

   T& get() {
      if(!data) data = create(std::index_sequence_for<Args...>());
      return *data;
   }

   template<std::size_t... I>
   std::unique_ptr<T> create(std::index_sequence<I...>)
   {
      return std::unique_ptr<T>{new T(std::get<I>(args)...)};
   }

private:
   std::tuple<typename std::decay<Args>::type...> args;
   std::unique_ptr<T> data;
};

我正在使用 C++14 的 std::index_sequence ,如果您的标准库实现没有提供这个,那么 SO(thisthis)上有几个示例展示了如何实现它。

最后一个辅助函数模板来构建LazyConstruct实例

template<class T, class... Args>
LazyConstruct<T, Args...> make_LazyConstruct(Args&&... args)
{
    return LazyConstruct<T, Args...>{std::forward<Args>(args)...};
}

Live demo


另一个基于Alf's answer的版本它使用 std::function,因此 LazyConstruct 的类型不会根据 T 的构造函数签名而改变。

template<class T>
struct LazyConstruct {
   template<class... Args>
   LazyConstruct(Args&&... args)
   : holder([this, args = std::make_tuple(std::forward<Args>(args)...)]() {
            return create(std::index_sequence_for<Args...>(), std::move(args));
       })
   {
   }

   T& get() {
      if(!data) data = holder();
      return *data;
   }

   template<std::size_t... I, class Tuple>
   std::unique_ptr<T> create(std::index_sequence<I...>, Tuple args)
   {
      return std::unique_ptr<T>{new T(std::get<I>(args)...)};
   }

private:
   std::function<std::unique_ptr<T>()> holder;
   std::unique_ptr<T> data;
};

Live demo

关于c++ - 带有转发的延迟初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26499863/

相关文章:

c++ - 如何让 showEvent() 被调用?

c++ - 生成范围内的随机数,不重复

c++ - 从共享对象调用外部类成员

C++——构建库

c++ - 欺骗 ARM 连接器将功能代码放入某些数据存储器中

c++11 - 继承和 OpenCL 的问题

c++ - C++(0x) 中是否存在无操作 "do nothing"函数对象?

c++ - 在嵌套的 lambda 中捕获通用的可调用对象 - 总是向前?

C++11 完美转发和引用折叠

c++ - 为什么不应该将 auto&& 用于局部变量?