我正在尝试实现一个惰性初始化类lazy<T>
,它存储T
的构造参数,并在第一次需要时使用它们来构造T
。目前我正在捕获函数对象(存储在boost::function
中)中的参数,该对象在调用时在指定位置构造对象;虽然这有效,但它需要动态分配,我想避免这种情况。
我想使用boost::variant
,其中不同的变体是与T
的各种构造函数对应的不同参数列表(假设没有任何模板构造函数)和T
本身,以便在编译时知道所需的内存量。为此,我需要一种编译时方法来汇编T
中所有可访问构造函数的列表。有没有办法做到这一点?
答案 0 :(得分:1)
这个答案中有两个半版本:
variant<>
,optional<>
和更新感谢@ 5gon12eder的评论我已经创建了这个基于Boost Variant的更优雅的版本:
请注意,Boost Variant也不使用动态内存分配。
<强> Live On Coliru 强>
#include <functional>
#include <boost/variant.hpp>
template <typename T>
struct Lazy {
template <typename... Args> Lazy(Args const&... args)
: _storage(Factory([=] { return T(args...); }))
{ }
T& get() { return ensure(); }
T const& get() const { return ensure(); }
explicit operator bool() const { return _storage.which(); }
private:
using Factory = std::function<T()>;
mutable boost::variant<Factory, T> _storage;
T& ensure() const {
if (!_storage.which())
_storage = boost::get<Factory>(_storage)();
return boost::get<T>(_storage);
}
};
#include <string>
#include <iostream>
int main() {
Lazy<std::string> ls("Hello world");
std::cout << ls.get() << "\n";
// Lazy<std::string> oops(42.7, true); // no matching function call
}
限制与Boost Optional一样(见下文)。请注意,对于变量,工厂将在实例化时被破坏,因此如果参数类型具有昂贵的析构函数,则可能需要牢记这一点。
When To Use Boost Optional
[...]
另一个典型的情况是表明我们还没有价值,但我们希望以后能有价值。这个概念可以用于实现延迟初始化或两阶段初始化等解决方案。
请注意,Boost Optional会不使用动态内存分配。
<强> Live On Coliru 强>
#include <functional>
#include <boost/optional.hpp>
template <typename T>
struct Lazy {
template <typename... Args> Lazy(Args const&... args)
: _factory([=] { return T(args...); })
{ }
T& get() { return *(_value? _value : _value = _factory()); }
T const& get() const { return *(_value? _value : _value = _factory()); }
explicit operator bool() const { return _value; }
private:
std::function<T()> _factory;
mutable boost::optional<T> _value;
};
#include <string>
#include <iostream>
int main() {
Lazy<std::string> ls("Hello world");
std::cout << ls.get() << "\n";
// Lazy<std::string> oops(42.7, true); // no matching function call
}
不可否认,这有局限性
类型删除function<>
可能仍会产生动态分配。有几个实现使用小对象缓冲区优化来优化小工厂仿函数,因此配置文件,配置文件,配置文件。
您可以考虑直接从来电者提供工厂仿函数:
请参阅此变体 Live On Coliru 。
请注意,它会对构造函数参数进行早期检测,因此类似
Lazy<std::string> oops(42.7, true);
根本就没有编译。
作为奖励,它具有类似智能指针的上下文转换为bool。您将需要添加更多内容(例如哈希&lt;&gt;特化,以及可能只遵循boost::optionals
IO运算符实现的IO运算符)