Defining element initialization order when constructing std::tuple

后端 未结 2 673
深忆病人
深忆病人 2021-01-25 18:10

I would like to store the initialization values for elements in a tuple inside a separate tuple, so that I can use the same values as a preset for other tuples of the respective

相关标签:
2条回答
  • 2021-01-25 18:23

    There is no requirement in the standard for the order of std::tuple member initialisation, I am afraid.

    You can iterate over a tuple in a specific order though, e.g.:

    #include <tuple>
    #include <iostream>
    
    #include <boost/fusion/adapted/std_tuple.hpp>
    #include <boost/fusion/algorithm/iteration/for_each.hpp>
    
    int main()
    {
        auto a = std::make_tuple(true, 42, 3.14, "abc");
        boost::fusion::for_each(a, [](auto& value) {
                std::cout << value << '\n';
            });
    }
    

    Outputs:

    1
    42
    3.14
    abc
    
    0 讨论(0)
  • 2021-01-25 18:28

    For anyone interested in a solution, I came up with a way to control the initialization order and retain the constness of elements:

    #include <tuple>
    
    template<typename... Elems>
        struct construct 
        {
            template<size_t... Ns, typename Head, typename... Rest>
                static constexpr const std::tuple<Rest...> 
                    drop_head_impl( const std::index_sequence<Ns...> ns, 
                        const std::tuple<Head, Rest...> tup )
                {
                    return std::tuple<Rest...>( std::get<Ns + 1u>( tup )... );
                }
    
            template<typename Head, typename... Rest>
                static constexpr const std::tuple<Rest...> 
                    drop_head( const std::tuple<Head, Rest...> tup )
                {
                    return drop_head_impl( std::make_index_sequence<sizeof...(Rest)>(), tup );
                }
    
            template<typename Head>
                static constexpr const std::tuple<Head> 
                    func_impl( const std::tuple<typename Head::initer_t> initer )
                {
                    return  std::tuple<Head>( { std::get<0>( initer ) } ); 
                }
    
            template<typename Head, typename Next, typename... Rest>
                static constexpr const std::tuple<Head, Next, Rest...> 
                    func_impl( const std::tuple<typename Head::initer_t, typename Next::initer_t, typename Rest::initer_t...> initer )
                {
                    std::tuple<Head> head( { std::get<0>( initer ) } ); 
                    return std::tuple_cat( head, func_impl<Next, Rest...>( drop_head(initer) ) );
                }
    
            static constexpr const std::tuple<Elems...> 
                func( const std::tuple<typename Elems::initer_t...> initer )
            {
                return func_impl<Elems...>( initer );
            }
        };
    
    // Elements are the end points of a Widget hierarchy
    struct Element
    {
        using initer_t = int;
        Element( const initer_t pIniter )
            :data{ pIniter }
        {
            printf( "Creating %i\n", data );
        }
        const initer_t data;
    };
    
    // A Widget class stores any number of Elements and/or other Widget instances
    template<typename... Elems>
        struct Widget
        {
            using initer_t = std::tuple<typename Elems::initer_t...>;
            Widget( const initer_t pIniter )
                :elements( construct<Elems...>::func( pIniter ) ) 
            {}
            const std::tuple<Elems...> elements;
        };
    
    int main()
    {
        using Button = Widget<Element, Element>;
        using ButtonList = Widget<Button, Button, Element>;
    
        Button::initer_t basic_button_initer{ 0, 1 }; // presets for Buttons
        Button::initer_t other_button_initer{ 2, 3 }; 
    
        ButtonList::initer_t buttonlist_initer{ basic_button_initer, other_button_initer, 4 }; //a preset for a ButtonList
    
        ButtonList buttonlist{ buttonlist_initer };
        return 0;
    }
    

    The construct structure takes the tuple of initer_ts (initer), constructs a tuple containing the first element of Elems... using the first element of initer, then drops the first element of initer and passes the remaining tuple to itself, which causes a tuple with the next element of Elems... to be constructed using the next element in initer. This recursion is stopped by an overload of func_impl for a tuple with one element which simply constructs that element from its initer_t in a tuple and returns it. This single-element tuple gets concatenated to the tuple with the previous element, the result gets returned to the higher level and is concatenated to the single-element tuple there and so on.

    0 讨论(0)
提交回复
热议问题