Copy an mpl::vector_c to a static array at compile time
Asked Answered
P

1

5

With C++11 i have the something like

#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/size.hpp>

#include <boost/array.hpp>

#include <iostream>

namespace mpl = boost::mpl;

template<std::size_t ... Args>
struct Test
{
            typedef mpl::vector_c<std::size_t, Args ...> values_type;

            static const boost::array<std::size_t, sizeof...(Args)> values;
};


int main (int argc, char** argv)
{
            Test<3,2,5,6,7> test;
            return 0;
}

I would like to initialize the boost::array contents with the values 'contained' in the mpl::vector_c. This initialization should be performed at compile time. I have seen on SO some solutions using the preprocessor, but I have no idea on how to apply them to the variadic template case.

Notice that in the above sample code, the elements of the mpl::vector_c are the same as Test's template parameters. In the actual code it is not the case, instead values_type has length == number of template arguments, but the actual values result from the application of a sequence of mpl algorithms. Therefore, do not assume that the argument are the same.

Hope the question is clear, thanks!

Pinole answered 31/5, 2012 at 9:0 Comment(0)
T
8

One method is to use at_c to extract the vector_c into a parameter pack, and then expand it and use it to initialize the array.

#include <cstdio>
#include <array>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/size.hpp>
#include <utils/vtmp.hpp>
// ^ https://github.com/kennytm/utils/blob/master/vtmp.hpp

template <typename MPLVectorType>
class to_std_array
{
    typedef typename MPLVectorType::value_type element_type;
    static constexpr size_t length = boost::mpl::size<MPLVectorType>::value;
    typedef std::array<element_type, length> array_type;

    template <size_t... indices>
    static constexpr array_type
            make(const utils::vtmp::integers<indices...>&) noexcept
    {
        return array_type{{
            boost::mpl::at_c<MPLVectorType, indices>::type::value...
        }};
    }

public:
    static constexpr array_type make() noexcept
    {
        return make(utils::vtmp::iota<length>{});
    }
};

int main()
{
    typedef boost::mpl::vector_c<size_t, 3, 2, 5, 6, 7> values;

    for (size_t s : to_std_array<values>::make())
        printf("%zu\n", s);
    return 0;
}

I am using std::array here, but you could simply change it to boost::array and it still works. The expression

to_std_array<MPLVector>::make()

is run in compile-time because the make() function is constexpr.


The same technique is usually used in expanding a std::tuple into a std::array ( Convert std::tuple to std::array C++11), into a function call ( "unpacking" a tuple to call a matching function pointer), etc.

Titer answered 31/5, 2012 at 10:0 Comment(6)
I am just curious about whether there is any advantage compared to for (size_t s : {3, 2, 5, 6, 7})?Gonad
@betabandido: No, they both compile to the same assembly (after optimization, of course).Titer
I guess that in a more complex usage of template metaprogramming, however, the approach shown in the question and your solution can actually be necessary, right? For instance, I am thinking in the situation when the array needs to be passed from one function to another. Would it be possible to use a plain array ({3, 2, ...}) in that case too?Gonad
@betabandido: I don't understand your question. Both array and initializer list can be iterated using range-based for.Titer
@KennyTM Your solution works great in my case. I would like to ask you what the syntax <code>array_type{{ ... }}</code> stands for in C++11? I'm just starting to use C++11 features (they really make my life simpler IMO), it is still hard to find a reasonably complete and accessible (for me) account of non-trivial usages of new features (NOT the standard)...Pinole
@CntrAltCanc: Uniform initialization. Ideally, One pair of { is enough (i.e. array_type{...}), but clang will produce an error.Titer

© 2022 - 2024 — McMap. All rights reserved.