构造std :: tuple时定义元素初始化顺序 [英] Defining element initialization order when constructing std::tuple

查看:100
本文介绍了构造std :: tuple时定义元素初始化顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将元素的初始化值存储在单独的元组内的元组中,以便可以将相同的值用作相应类型的其他元组的预设。

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 type.

对我的程序而言,元组元素的构造函数以从左到右的顺序调用是非常重要的(否则,它充其量是非常令人困惑的)。

It is very important to my program that the constructors of the tuple elements are called in left-to-right order (otherwise it would at best turn out very confusing).

这是我程序的简化版本:

Here is a simplified version of my program:

#include <tuple>

// 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{ 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;
}

所以我正在初始化 std :: tuple<元素...> Widget< Elems ...> 的元素成员和 std :: tuple< typename Elems :: initer_t。 ..> Widget< Elems ...> 的构造函数初始化列表中。
应该用 initer_t 定义的类型的相应初始化值来初始化 elements 的每个元素。使用pIniter中的值。
initer_t 类型是Widget层次结构中每个成员的类型(例如 Widget< typename ...> Element ),这是初始化层次结构成员的类型。
但是这种情况发生的顺序是从右到左,而我需要从左到右。

So I am initializing the std::tuple<Elems...> elements member of Widget<Elems...> with a std::tuple<typename Elems::initer_t...> in Widget<Elems...>'s constructor initialization list. This is supposed to initialize each element of elements with its corresponding initialization value of the type defined by initer_t using the values in pIniter. The initer_t type is a type for each member of a Widget hierarchy(for example a Widget<typename...> or an Element), which is the type that the hierarchy member should be initialized with. But the order in which this happens is right-to-left, while I need it in left-to-right.

程序的输出是

Creating 4
Creating 3
Creating 2
Creating 1
Creating 0

但是我想撤销此顺序。

在这种情况下,我该怎么办?

How can I do this in this case?

推荐答案

对于对解决方案感兴趣的人,我想出了一种方法控制初始化顺序并保留 elements 的常数:

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;
}

构造结构接受 initer_t s(初始值)的元组,构造一个包含 Elems ... 的第一个元素的元组。 initer的第一个元素,然后删除initer的第一个元素,并将剩余的元组传递给自身,这将导致使用下一个 Elems ... 元素的元组initer中的下一个元素。对于具有一个元素的元组, func_impl 的重载停止了此递归,该元组只是从 initer_t 中构造该元素一个元组并返回它。该单元素元组被连接到具有前一个元素的元组,结果被返回到更高的级别,并被连接到那里的单元素元组,依此类推。

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.

这篇关于构造std :: tuple时定义元素初始化顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆