采取可能具有以下接口(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

09-06 23:20