这里有一点点复杂的做你想做的事情。基本想法是让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(this或this)的几个例子。
最后一个辅助函数模板构建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
你允许假设传递的左值的引用将是有效的,当'GET'叫? – Pradhan 2014-10-22 03:48:45
是的。或者更具体地说,如果不是,则行为是未定义的。 (就像在任何其他情况下的ref绑定) – Nick 2014-10-22 12:58:13