2012-02-29 150 views
4

考虑下面的代码来自动生成Boost.MPL类型序列(列表或向量)。生成巨大的Boost.MPL类型序列

#include <iostream>      // cout 
    #include <boost/mpl/for_each.hpp>  // for_each 
    #include <boost/mpl/identity.hpp>  // identity, make_identity 
    #include <boost/mpl/int.hpp>   // int_ 
    #include <boost/mpl/list.hpp>   // list 
    #include <boost/mpl/next.hpp>   // next 
    #include <boost/mpl/push_front.hpp>  // push_front 
    #include <boost/mpl/vector.hpp>   // vector 

    template<size_t, typename> struct iota_n; 

    template<typename Value> 
    struct iota_n<0, Value> 
    : 
      boost::mpl::list<>  // can change this to boost::mpl::vector<> 
    {}; 

    template<size_t N, typename Value> 
    struct iota_n 
    : 
      boost::mpl::push_front< typename 
        iota_n< 
          N - 1, typename 
          boost::mpl::next<Value>::type 
        >::type, 
        Value 
      > 
    {}; 

    // works for N <= 20 and boost::mpl::vector 
    // works for N <= 247 and boost::mpl::list 
    typedef iota_n< 247, boost::mpl::int_<0> >::type sequence; 

    struct print 
    { 
      template<typename T> 
      void operator()(boost::mpl::identity<T>) 
      { 
        std::cout << T::value << "\n"; 
      } 
    }; 

    int main() 
    { 
      boost::mpl::for_each<sequence, boost::mpl::make_identity<> >(
        print() 
      ); 
      std::cout << BOOST_MPL_LIMIT_LIST_SIZE << '\n';   // 20 on my system 
      std::cout << BOOST_MPL_LIMIT_VECTOR_SIZE << '\n';  // 20 on my system 
      return 0; 
    } 

按照Boost.MPL文档中,boost::mpl::list序列最多可以有BOOST_MPL_LIMIT_LIST_SIZE元素,同样的boost::mpl::vector编译器可以达到BOOST_MPL_LIMIT_VECTOR_SIZE。这两个宏在我的系统上评估为20。

MSVC++ 2010和Boost 1.47.0确实无法生成超过记录的20个元素的向量。但令人惊讶的是,它可以生成多达247个元素的列表!

有谁知道为什么会发生这种情况?

+1

只是一个猜测,但我认为这是更困难,并涉及更多的元编程来实现一个mpl向量比一个链接列表,它可以只包含一个简单的两个参数模板。对我来说,mpl列表能够处理更多的元素并不令人惊讶,因为这些模板更简单,实例化可能更少,静态递归和分支也更少。 – stinky472 2012-02-29 23:19:06

+0

那么在那种情况下,为什么限制向量和列表序列的宏不同?在我的系统上,都是20,但我可以生成多达247个元素的列表! – TemplateRex 2012-03-01 20:11:23

+0

这些宏可能会根据增强型作者通常可以安全地支持各种编译器的情况而设置实际限制。您可以继续使用列表的事实可能仍然超出了boost作者希望您编写可移植代码的做法。 – stinky472 2012-03-01 23:29:23

回答

5

作为每the docsBOOST_MPL_LIMIT_xxx_SIZE指定了序列的可变参数形式(例如list<>)的限制;编号为表格(例如list42<>)的没有预定义的最高限制,除了编译器对模板参数的限制。好的,后一种说法并不完全准确:实际上,在默认库配置中,对使用​​预先生成的预处理头进行编号形式的限制;请参阅this post关于如何提起它。

后续:@rhalbersma您似乎将两个单独的概念捆绑在一起:列表元素的最大数目与list的“构造函数”的最大元素数量。 BOOST_MPL_LIMIT_LIST_SIZEcontrols the latter,而不是前者,两者之间确实没有依赖关系。你上面的代码正在测试前者;最大的模板元素是一个完全不同的野兽。

MPL序列首先存在一个arity限制的原因是该库必须模拟可变参数模板(它是在C++ 11之前编写的),这通常是by defaulting unused arguments to some auxiliary type and providing a bunch of specializations to weed out those unused arguments before constructing the actual sequence。这样做的代价是默认参数通常显示在错误消息中并且掩盖了其他所有内容,并且大量的特化对编译时间有显着影响。 IOW,你不得不在某个地方停下来,那时你似乎不太可能需要将超过20个序列元素传递给序列的“构造函数”(如果你这样做了,总会有数字形式),因此当前限制。

+0

是的,我知道如何更改限制宏。但是,在我的系统中,列表的宏等于20,但我可以生成多达247个元素的列表!并且iota_n <248, ...>的错误消息提到了序列=列表<...>,而不是列表248 <...>。所以我仍然不明白宏为什么不把列表限制为20,就像它与vector <>一样。 – TemplateRex 2012-03-01 20:10:07

+1

@rhalbersma曾尝试将你的代码移植到不同的编译器上?现在看到的这些限制不是基于某种标准的语言限制,而是编译器的限制。推送你的编译器的模板递归限制绝对不会产生非常便携的代码。 – stinky472 2012-03-01 23:32:04

+0

@ stinky472我曾经与Eclipse/CDT(使用gcc和Intel编译器)并行构建,但Ubuntu在C++库(我大量使用我的项目中的C++ 11功能)方面稍显迟缓。我应该重试,谢谢。 – TemplateRex 2012-03-02 10:05:53