Boost :: MPL的实际使用示例?

And*_*hko 27 c++ boost boost-mpl

你能否分享Boost :: MPL用法的任何实际例子(lambdas除外),只是为了让我更好地理解它的用途和实际应用领域?MPL文档教程有一个维度分析示例,但也许是因为它是一个这样的学术示例,它没有让我感觉到Boost :: MPL以及何时可以有效地使用它.

Mat*_* M. 14

事实上,像Boost.Preprocessor一样,Boost.MPL实际上是构建块.

大多数情况下,您可能通过其他库使用它,因为许多Boost库都是基于这两个库构建的.

例如:

  • Boost.Fusion(跨越编译时和运行时域之间的空白)
  • Boost.MultiIndex(用于更简单的界面)
  • Boost.Unit(用于尺寸分析)
  • 我认为,Boost.Variant也可能依赖于它

你可能已经知道了:)


jal*_*alf 13

我已经使用Boost.Mpl来生成类似变体的类.

例如,给定一个MPL类型列表,例如:

typedef boost::mpl::set<Foo, Bar, Baz> type_set;
Run Code Online (Sandbox Code Playgroud)

然后boost::mpl::fold,我用它来构建一个派生的类链,每个类都添加一个std::unordered_set类型集中的类型之一.最终结果是一个包含a unordered_set<Foo>,an unordered_set<Bar>和an的类unordered_set<Baz>.

并且因为类是用a来指定的boost::mpl::set,所以我可以遍历这些类型以自动生成其他函数,例如operator==比较所有unordered_sets的函数.


Bai*_*ang 6

在构建匹配引擎时,主要是针对交易区的交易所或暗池,我们通常需要检查2个订单是否匹配(或者我们说是否可以交叉),检查可能有很多方面我们称之为Rules,这里是组织这些规则的关键要求:

  • 添加新规则并应用应该很容易
  • 将规则组织成不同的组以应用检查应该很方便
  • 因为规则检查被频繁调用——当然,这是匹配引擎的唯一工作,我们希望它尽可能优化

这非常适合使用 boost mpl,它可以使用编译时间序列boost::mpl::vector 来组织规则,并使用boost::mpl::for_each.

这个想法最好用一个例子来说明:

  • 通过简单地定义一个新的 Rule 类来添加新规则是直接的
  • 使用 方便对规则进行分组boost::mpl::vector,并将其用作模板参数进行canCross检查
  • 因为大部分设置工作都是在编译时完成的,所以速度很快。
#include <iostream>
#include <vector>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>

using namespace std;

struct Order {};

struct Rule1
{
    const char* name() const { return "Rule1"; }
    bool apply(const Order& a, const Order& b) const {  cout << "Checking Rule1..." << endl; return true; }
};

struct Rule2
{
    const char* name() const { return "Rule2"; }
    bool apply(const Order& a, const Order& b) const {  cout << "Checking Rule2..." << endl; return false;}
};

struct Rule3
{
    const char* name() const { return "Rule3"; }
    bool apply(const Order& a, const Order& b) const {  cout << "Checking Rule3..." << endl; return false;}
};

struct Rule4
{
    const char* name() const { return "Rule4"; }
    bool apply(const Order& a, const Order& b) const {  cout << "Checking Rule4..." << endl; return true;}
};

struct RuleApplicator
{
    RuleApplicator(bool& success, std::vector<const char*>& failedRules, const Order& order1, const Order& order2):
        _success(success),
        _failedRules(failedRules),
        _order1(order1),
        _order2(order2)
    {}
    template <typename U> void operator() (U rule)
    {
        if(!rule.apply(_order1, _order2))
        {
            _success = false;
            _failedRules.push_back(rule.name());
        }
    }

private:
    bool& _success;
    std::vector<const char*>& _failedRules;
    const Order& _order1;
    const Order& _order2;
};

template <class Rules>
bool canCross(const Order& a, const Order& b)
{
    bool success = true;
    std::vector<const char*> failedRules;
    RuleApplicator applicator(success, failedRules, a, b);
    boost::mpl::for_each<Rules>(applicator);
    if (!success)
    {
        cout << "Can't cross due to rule check failure:";
        for(const char* ruleName: failedRules)
        {
            cout << ruleName << " ";
        }
        cout << endl;
        return false;
    }
    else
    {
        cout << "Can cross!" << endl;
        return true;
    }
}

int main(int argc, char** argv)
{
    Order a, b;
    canCross<boost::mpl::vector<Rule1, Rule4>>(a, b);
    cout << endl;
    canCross<boost::mpl::vector<Rule1, Rule2, Rule3, Rule4>>(a, b);
}


Run Code Online (Sandbox Code Playgroud)

您将看到输出为:

Checking Rule1...
Checking Rule4...
Can cross!

Checking Rule1...
Checking Rule2...
Checking Rule3...
Checking Rule4...
Can't cross due to rule check failure:Rule2 Rule3
Run Code Online (Sandbox Code Playgroud)


Edw*_*nge 5

我使用了一个更增强的尺寸分析库,称为Boost.Units。

我已经开发了一个编译时反射库,然后使用该库构建了一个通用类,该类为传入的任何编译时反射类型提供运行时反射。我使用了该支持来自动生成UI组件以编辑属性这种反射类型。

这对于我们应用程序中事件的分发也至关重要。例如,当有人更改他们希望系统放入的单位时,我不必告诉系统已将新项目添加到给定设备中,因为代码使用MPL分析了这些类型并且只知道已添加了一些内容并更改它。

我刚刚使用元编程技术将Qt信号包装为某种东西,以重新获得其系统删除的类型安全性,并能够与任何功能实体连接。

但是说实话,当您使用诸如sort之类的标准算法时,几乎可以肯定已经使用了实用的元编程技术。排序算法的一种不错的实现方式是使用元编程的较少发展形式来分析传入的迭代器,然后使用标记分派来启动能够充分利用这些迭代器功能的排序算法。

坦率地说,如果您不进行元编程,那么您就不会利用C ++的强大功能,并且还可能会使用其他功能。

  • 我认为问题是关于Boost.MPL,而不是一般的元编程。 (2认同)
  • 但是您可以问“您是否使用Boost.MPL”而不问“您是否使用模板元编程的任何其他示例”,就像您可以问“您是否驾驶沃尔沃”而不问“您是否驾驶汽车”一样吗? (2认同)

Bai*_*ang 5

如果您的应用程序在处理键值对时有繁重的逻辑,您将需要一种从键中获取值的超高效方法,典型的 hashmap 效果很好,但如果可能的键预先已知,则可以使用 boost::mpl 进行优化,使用数组和在编译时将键转换为数组索引的方法,这当然更有效。

下面是一个处理fix message的例子,它是一个包含各种键值对的消息,它在金融交易应用程序中被大量使用:

#include <iostream>
#include <array>
#include <string>
#include <unordered_set>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/integral_c.hpp>
#include <boost/mpl/size.hpp>

using namespace std;
using namespace boost;


struct TagEntity
{
    bool isValid;
    std::string value;
};

template<class CommonTags>
struct FixMsg
{
    static constexpr uint32_t CommonTagsCount = mpl::size<CommonTags>::type::value;

    template<int Tag>
    constexpr uint32_t index()
    {
        constexpr auto idx = mpl::find<CommonTags, mpl::integral_c<int, Tag>>::type::pos::value;  // this is the key step: convert tag to index in compile time
        static_assert(idx < CommonTagsCount, "tag not found");
        return idx;
    }
    template<int Tag>
    TagEntity& getTagEntity()
    {
        return _commonTags[index<Tag>()];
    }

    std::array<TagEntity, CommonTagsCount> _commonTags; // or else use std::unordered_set, which is not as fast as this approach: absolute O(1) in runtime
};


int main(int argc, char** argv)
{
    using MyCommonTags = mpl::vector_c<int,
          11,
          35,
          10914,
          10916>;

    FixMsg<MyCommonTags> fixMsg;
    auto& tagEntity = fixMsg.getTagEntity<11>();
    tagEntity.isValid = true;
    tagEntity.value = "Get tag entity in O(1)";

    cout << tagEntity.value << endl;

Run Code Online (Sandbox Code Playgroud)