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

时间:2011-01-09 11:42:13

标签: c++ boost boost-mpl

您能否分享Boost::MPL用法(lambda除外)的任何实际示例,只是为了让我更好地了解其用途和实际应用领域? MPL文档教程有一个dimensional analysis示例,但也许是因为它是一个学术性的例子,它没有让我感觉到Boost :: MPL以及何时可以有效地使用它。

8 个答案:

答案 0 :(得分:13)

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

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

例如:

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

你可能已经不知名地使用它了:)

答案 1 :(得分:11)

我使用Boost.Mpl生成类似变体的类。

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

typedef boost::mpl::set<Foo, Bar, Baz> type_set;

然后我使用boost::mpl::fold来构建从彼此派生的类链,每个类都添加类型集中其中一种类型的std::unordered_set。最终结果是一个包含unordered_set<Foo>unordered_set<Bar>unordered_set<Baz>的类。

因为类是根据boost::mpl::set指定的,所以我可以迭代这些类型以自动生成其他函数,例如operator==比较所有unordered_set }第

答案 2 :(得分:4)

我使用了一个名为Boost.Units的更强大的维度分析库。

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

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

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

但是说实话,当你使用像sort这样的标准算法时,你几乎肯定已经使用了实际应用的元编程技术。排序算法的一个不错的实现是使用一种不太进化的元编程形式来分析传入的迭代器,然后使用标签调度来启动能够充分利用这些迭代器的特性的排序算法。

坦率地说,如果你没有进行元编程,那么你就不会利用C ++的强大功能,你也可以使用别的东西。

答案 3 :(得分:3)

要添加到Matthieu的答案,它在Boost.PythonLuabind中也得到了广泛的使用。

答案 4 :(得分:3)

我在stat_log库中广泛使用boost :: mpl(和boost :: fusion)。该库允许用户指定统计和日志标记及其相关行为的层次结构,即每标记统计类型(直方图,计数器等)。

我非常依赖元编程来做正确的事情:

stat_log::writeStat<IP_PKTS_RCVD>(450);

例如,如果用户定义了特征类型:

template <>
struct stat_tag_to_type<IP_PKTS_RCVD>
{
   using type = Accumulator<
        stat_log::HistogramCount<
            int,
            1, //start bin
            1500, //stop bin
            10 //num_bits
        >
     >;
};

上面的“writeStat”调用将代理(在编译时)直方图统计。这种设计技术的强大之处在于“writeStat”调用站点根本没有与所选择的特定统计数据相结合。

我还使用丰富的MPL和boost :: fusion来实际查看统计数据。根据您的问题,请参阅以下文件,了解最高浓度的boost :: mpl:

https://github.com/rjmccabe3701/stat_log/blob/master/include/stat_log/util/stat_log_impl.h https://github.com/rjmccabe3701/stat_log/blob/master/include/stat_log/util/tag_commander.h https://github.com/rjmccabe3701/stat_log/blob/master/include/stat_log/stat_log.h

特别是stat_log_impl.h中的漂亮模板元“函数”:

//This template is used in conjunction with an MPL algorithm
// with the same semantics as mpl::find_if.
//BoolFunc is the "condition" metafunction.
//StatTagFunc is a metafunction that transforms the given
//   stat_tag into something the algorithm requires.
//   For example the "Identity" metafunction would work here.
//StatTagArgs is extra arguments to the BoolFunc
template <template<typename...> class BoolFunc,
          template<typename...> class StatTagFunc,
          class... StatTagArgs>
struct tag_node_query
{
   template<typename TheTagNode>
   struct apply
   {
      using stat_tag = typename TheTagNode::tag;
      using type = std::integral_constant
         <
            bool,
            BoolFunc<
               typename StatTagFunc<stat_tag>::type,
               StatTagArgs...
            >::value
         >;
   };
};

答案 5 :(得分:2)

我做的很有趣: https://github.com/edubois/static-factorial/blob/master/main.cpp

它使用boost :: mpl的一小部分静态计算factorial&lt; 8&gt;()的值......

这有助于理解主要观点。

答案 6 :(得分:2)

在构建匹配引擎(主要用于交易区域中的Exchange或DarkPool)时,我们通常需要检查2个订单是否匹配(或者说是否可以交叉),可能有很多方面需要检查我们称为规则,以下是组织这些规则方面的关键要求:

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

这非常适合使用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);
}


您将看到以下输出:

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

Checking Rule1...
Checking Rule2...
Checking Rule3...
Checking Rule4...
Can't cross due to rule check failure:Rule2 Rule3

答案 7 :(得分:2)

如果您的应用程序在处理键值对时逻辑繁重,那么您将需要一种超高效的方法来从键值中获取值,典型的哈希图可以很好地工作,但是如果预先知道可能的键,则可以使用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;