3

I want to generate boost fusion type sequences with more than 50 elements. The contents of boost/fusion/container/vector/vector50.hpp seems to suggest that a macro BOOST_FUSION_DONT_USE_PREPROCESSED_FILES might be used to affect this limit somehow.

I have created the following simple program which pushes back an int onto a boost::fusion::vector type for a specified number of times, and then converts the result to a vector (which triggers the error).

#include <boost/fusion/container.hpp>                                              
#include <boost/fusion/algorithm.hpp>                                              

#include <type_traits>                                                             

template <typename Sequence, int N>                                                
struct PushBack                                                                    
{                                                                                  
    using type = typename PushBack<typename boost::fusion::result_of::push_back<Sequence, int>::type, N-1>::type;
};                                                                                 

template <typename Sequence>                                                       
struct PushBack<Sequence, 0>                                                       
{                                                                                  
    using type = Sequence;                                                         
};                                                                                 

int main()                                                                         
{                                                                                  
    using NullVector = boost::fusion::vector<>;                                    
    using Sequence = boost::fusion::result_of::as_vector<typename PushBack<NullVector, 20>::type>::type; // this line triggers the error

    Sequence s;                                                                    
    return 0;                                                                      
}                          

When I run this with -D BOOST_FUSION_DONT_USE_PREPROCESSED_FILES -D FUSION_MAX_VECTOR_SIZE=100 I get a flood of errors that look roughly like this:

.../boost/fusion/container/generation/make_vector.hpp:105:25: error: ‘vector51’ does not name a type .../boost/fusion/container/generation/make_vector.hpp:105:25: error: ‘vector52’ does not name a type .../boost/fusion/container/generation/make_vector.hpp:105:25: error: ‘vector...’ does not name a type

Clearly I'm not doing it right. How do I extend this limit past 50? I need at least 150...

quant
  • 21,507
  • 32
  • 115
  • 211
  • Okay - updated my answer, it is indeed possible to workaround the limitation imposed by both mpl and fusion, see my edit.. – Nim Oct 15 '14 at 13:35

3 Answers3

2

This is a two step approach, firstly define: BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS in your compilation flags, and then also set the size you require with -DBOOST_MPL_LIMIT_VECTOR_SIZE=50 -DFUSION_MAX_VECTOR_SIZE=50 (nearest 10)

EDIT:

You are indeed out of luck, in the headers, even if you don't use preprocessed headers, looks like it's limited to 50 by this chunk of code:

#if (FUSION_MAX_VECTOR_SIZE > 40)
#include <boost/fusion/container/vector/vector50.hpp>
#endif

Which then does the really dumb thing:

#define BOOST_PP_FILENAME_1 <boost/fusion/container/vector/detail/vector_n.hpp>
#define BOOST_PP_ITERATION_LIMITS (41, 50)
#include BOOST_PP_ITERATE()

}}

Hmm.. I don't think there is a way around other than "patching" the above code..

EDIT2: Well, where there is a will to hack, there is apparently a way (without having to modify boost), it does come with a huge disclaimer - test properly, it compiles, and you can access elements beyond 50, that's about all the warranty I'll provide...

#include <iostream>

#define BOOST_MPL_LIMIT_VECTOR_SIZE 50
#define FUSION_MAX_VECTOR_SIZE 60

// This sets us up with mpl vector up to 50
#include <boost/mpl/vector.hpp>

// This adds the missing chunk - you should be able to expand this up to template depth
// This sets up the sequence of vectors (vector1 : T + vector0 etc.
#include <boost/fusion/sequence/intrinsic/begin.hpp>
namespace boost { namespace mpl {

#   define BOOST_PP_ITERATION_PARAMS_1 \
    (3,(51, 60, <boost/mpl/vector/aux_/numbered.hpp>))
#   include BOOST_PP_ITERATE()

}}
// This sets up the specializations
#define AUX778076_SEQUENCE_BASE_NAME vector
#   define AUX778076_SEQUENCE_LIMIT BOOST_MPL_LIMIT_VECTOR_SIZE
#   define AUX778076_SEQUENCE_CONVERT_CN_TO(z,n,TARGET) TARGET(BOOST_PP_CAT(C,n))
#   include <boost/mpl/aux_/sequence_wrapper.hpp>

// Include everuthing up to vector50
#define BOOST_FUSION_DONT_USE_PREPROCESSED_FILES
#include <boost/fusion/container/vector/vector50.hpp>

// Add the missing range
namespace boost
{
namespace fusion
{
struct vector_tag;
#define BOOST_PP_FILENAME_1 <boost/fusion/container/vector/detail/vector_n.hpp>
#define BOOST_PP_ITERATION_LIMITS (51, 60)
#include BOOST_PP_ITERATE()
}
}

// Declare the vector class using the FUSION_MAX_VECTOR_SIZE, as the types themselves have been declared above, all is
// good in the world of fusion
#include <boost/fusion/container/vector/vector.hpp>


// Test access
#include <boost/fusion/sequence/intrinsic/at_c.hpp>


int main()
{

  using Sequence = typename boost::fusion::vector<
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    int,
    double,
    std::string,
    std::string
 >;

 Sequence s;

 std::cout << boost::fusion::at_c<51>(s) << std::endl;

}

Basically, all I'm doing above is filling in the missing bits (for counts bigger than 50) but instantiating the bits of mpl and fusion as needed. The above sequence of operations is pretty rigid, if anyone can distill it further - please update...

(NOTE: tested with gcc-4.8.2, boost-1.55, c++11)

Nim
  • 33,299
  • 2
  • 62
  • 101
  • And if I require it to be larger than 50? Will this still work (I'm not at my pc right now)? – quant Oct 14 '14 at 09:58
  • The theoretical maximum of template parameters is controlled by your compiler (for ansi compliance, IIRC, this is set to 1024 for c++11), in GCC for example I think it's defaulted to 900, but in reality is governed by how many the compiler can handle before it stack overflows! In GCC, you can control it with `-ftemplate-depth=n` (IIRC) – Nim Oct 14 '14 at 10:02
  • More than just fishy, IMO. It's tantamount to defining a struct with that many members. Thought tantalizing to my curiosity, I can't come up with a use case that I wouldn't either reject in code review, or replace with a proper codegen. – sehe Oct 14 '14 at 11:30
  • @Nim Thanks for the feedback. I encourage you to read about the applications of template metaprogramming in functional DSLs. – quant Oct 14 '14 at 11:51
  • @quant, have you looked at boost proto? – Nim Oct 14 '14 at 12:09
  • @Nim, yes, I did look at it briefly but I didn't see how it would avoid this problem. Could you explain? – quant Oct 14 '14 at 20:20
  • @Nim, your answer doesn't appear to work, I am still receiving errors. For example, when I set the limit to `60` I get an error stating that `vector60.hpp` can't be found... – quant Oct 14 '14 at 21:20
0

Looks to me the pre-processed files are merely a compilation time optimization.

In this case you'd probably want (?) to boldly go where no one has gone before and either:

  • edit the limits in that file:

    namespace boost { namespace fusion
    {
        struct vector_tag;
        struct fusion_sequence_tag;
        struct random_access_traversal_tag;
    
    // expand vector41 to vector50
    #define BOOST_PP_FILENAME_1 <boost/fusion/container/vector/detail/vector_n.hpp>
    #define BOOST_PP_ITERATION_LIMITS (41, 100)
    #include BOOST_PP_ITERATE()
    
    }}
    
  • add more headers in similar vein, e.g. a vector60.hpp, vector70.hpp... and include it in the proper places

I haven't tested this, but it's worth a try

sehe
  • 374,641
  • 47
  • 450
  • 633
  • I encountered the same error when modifying this file, but I'm not sure I did it properly. I wasn't able to find any documentation on how this _should_ be done so my next step is to bypass fusion/mpl altogether... – quant Oct 14 '14 at 22:17
0

It does not appear to be possible to extend this limit without either hacking into boost or using the boost wave preprocessor, neither of which are feasible options for me. The only real solution here is to adapt std::tuple to use mpl features and use that instead of fusion containers. This answer shows exactly how to do that:

https://stackoverflow.com/a/15865204/1613983

Community
  • 1
  • 1
quant
  • 21,507
  • 32
  • 115
  • 211