创建类的所有构造函数的类型列表

时间:2015-01-08 23:49:24

标签: c++ boost template-meta-programming

我正在尝试实现一个惰性初始化类lazy<T>,它存储T的构造参数,并在第一次需要时使用它们来构造T。目前我正在捕获函数对象(存储在boost::function中)中的参数,该对象在调用时在指定位置构造对象;虽然这有效,但它需要动态分配,我想避免这种情况。

我想使用boost::variant,其中不同的变体是与T的各种构造函数对应的不同参数列表(假设没有任何模板构造函数)和T本身,以便在编译时知道所需的内存量。为此,我需要一种编译时方法来汇编T中所有可访问构造函数的列表。有没有办法做到这一点?

1 个答案:

答案 0 :(得分:1)

这个答案中有两个半版本:

  • 基于variant<>
  • 基于optional<>
  • 一个实际上没有获取构造函数参数的版本,而是一个工厂可调用的版本。这可能会使动态分配更多地减少(但与问题略有不同)

Boost Variant

更新感谢@ 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一样(见下文)。请注意,对于变量,工厂将在实例化时被破坏,因此如果参数类型具有昂贵的析构函数,则可能需要牢记这一点。

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
}

不可否认,这有局限性

  • 没有正确扣除大括号初始化列表,
  • 构造函数参数必须是可复制的(使用c ++ 14时,这个限制可能不需要太多努力就可以解除)。
  • 类型删除function<>可能仍会产生动态分配。有几个实现使用小对象缓冲区优化来优化小工厂仿函数,因此配置文件,配置文件,配置文件

    您可以考虑直接从来电者提供工厂仿函数:
    请参阅此变体 Live On Coliru

    • 在某种程度上,这只会改变负担 - 这可能是也可能不重要
    • 在呼叫现场使用它似乎相当不太友好

请注意,它会对构造函数参数进行早期检测,因此类似

Lazy<std::string> oops(42.7, true);

根本就没有编译。

作为奖励,它具有类似智能指针的上下文转换为bool。您将需要添加更多内容(例如哈希&lt;&gt;特化,以及可能只遵循boost::optionals IO运算符实现的IO运算符)