为什么没有分段的元组结构?

时间:2020-12-20 00:30:10

The standard templates std::pair and std::array are special cases of std::tuple, and it stands to reason that they should have a very similar set of capabilities.

标准模板std::pair和std::array是std::tuple的特殊情况,因此它们应该具有非常相似的功能。

However, uniquely among the three, std::pair allows for piecewise construction. That is, if the types T1 and T2 can be constructed from a set of arguments a1, a2, ... and b1, b2, ..., then morally speaking we can make a pair

然而,在这三者中,唯一的是std::pair允许分段构造。也就是说,如果类型T1和T2可以由一组参数a1、a2、……和b1、b2、…从道德上讲,我们可以做一对

"pair<T1, T2> p(a1, a2, ..., b1, b2, ...)"

directly. Practically, this is spelt out as something like this:

直接。实际上,它是这样的:

std::pair<T1, T2> p(std::piecewise_construct,
                    std::forward_as_tuple(a1, a2, ...),
                    std::forward_as_tuple(b1, b2, ...));

Question: Why doesn't the same piecewise constructibility exist for arrays and tuples? Is there a profound reason, or is this a plain omission? For example, it would be nice to have:

问:为什么数组和元组没有同样的分段构造性呢?这是一个深刻的原因,还是一个明显的遗漏?例如:

std::tuple<T1, T2, T3> t(std::piecewise_construct,
                         std::forward_as_tuple(a1, a2, ...),
                         std::forward_as_tuple(b1, b2, ...),
                         std::forward_as_tuple(c1, c2, ...));

Is there a reason this cannot be done? [Edit: Or am I misunderstanding the purpose of piecewise construction entirely?]

这有什么不可能实现的原因吗?[编辑:还是我完全误解了分段施工的目的?]

(I do really have a situation in which I would like to initialize a vector of tuples with a defaulted element value which I would prefer to construct directly from the arguments, without spelling out each tuple element type again.)

(我确实有这样一种情况:我想用一个默认的元素值初始化元组向量,我宁愿直接从参数中构造它,而不需要重新拼写每个元组元素类型)。

3 个解决方案

#1


15  

Question: Why doesn't the same piecewise constructibility exist for arrays and tuples?

问:为什么数组和元组没有同样的分段构造性呢?

My recollection is that piecewise construction was added to std::pair for one reason only: to support uses-allocator construction of the pair elements, i.e. to allow an allocator to be provided and conditionally passed to the elements if they support construction with an allocator (see [allocator.uses] in the standard).

我记得,分段构造被添加到std::pair中,原因只有一个:支持对元素的uses-allocator构建,即允许提供一个分配器,并有条件地传递给支持分配器的元素(参见[allocator])。使用标准)。

At one point during the C++0x process std::pair had twice as many constructors as it does now, with every constructor having a corresponding "allocator-extended" version taking a std::allocator_arg_t and an allocator argument e.g.

在c++ 0x进程std:::pair中有两倍于现在的构造函数,每个构造函数都有一个对应的“allocator-extended”版本,使用std::allocator_arg_t和一个allocator参数,例如。

template<class T, class U>
  struct pair {
    pair();
    pair(allocator_arg_t, const Alloc&);
    template<class TT, class UU>
      pair(TT&&, UU&&);
    template<class Alloc, class TT, class UU>
      pair(allocator_arg_t, const Alloc&, TT&&, UU&&);
    // etc.

There was something of a running joke (haha, only serious) about the insane complexity of std::pair. The support for passing allocators to the elements was removed from std::pair and moved into std::scoped_allocator_adaptor, which is responsible for detecting whether the elements should be constructed with an allocator (see the construct overloads taking a pointer to std::pair in [allocator.adaptor.members]).

关于std:::pair这种疯狂的复杂性,有一个笑话(哈哈,只是认真的)。将分配器传递给元素的支持从std::pair中删除,并转移到std::scoped_allocator_adaptor中,该适配器负责检测是否应该使用分配器构造元素(参见在[allocator.adaptor.members]中使用指向std:::pair的构造重载)。

A nice consequence of the piecewise construction is that you can do "emplace" style initialization of pair elements, allowing pairs of non-movable, non-copyable types, but as far as I know that was not the goal of the design.

分段构造的一个很好的结果是,您可以对成对元素进行“emplace”样式的初始化,允许对不可移动的、不可复制的类型,但据我所知,这并不是设计的目标。

So the reason tuple doesn't support it is that the feature was invented to simplify pair which had ballooned from a very simple type in C++03 to a laughing stock in C++0x, but doing the same for tuple was not considered as important (it was new for C++11 anyway). Also, extending scoped_allocator_adaptor to handle tuples of arbitrary numbers of elements would have made that adaptor much more complicated.

因此,tuple不支持它的原因是,这个特性是为了简化一对,它们从c++ 03中的一个非常简单的类型膨胀到c++ 0x中的一个笑柄,但是对tuple做同样的操作并不重要(它对c++ 11来说是新的)。此外,扩展scoped_allocator_adaptor以处理任意数量的元素元组,会使适配器变得更加复杂。

As for std::array, that's an aggregate type (because reasons) so adding a constructor taking piecewise_construct_t is not possible without making it a non-aggregate.

至于std:::array,这是一个聚合类型(因为原因),所以如果不使它成为非聚合,就不可能添加使用piece ewise_construct_t的构造函数。

#2


12  

I'm not sure why it's not there. Previously, I thought that the implementation wouldn't be possible, given the current varadic template syntax, but I realized that it can be done if it's broken into pieces.

我不知道为什么没有。以前,我认为考虑到当前的可变模板语法,实现是不可能的,但我意识到,如果它被分解为多个部分,那么实现是可以实现的。

If they had defined an interface like this:

如果他们定义了这样的接口:

template<typename... T>
tuple(piecewise_construct, T&&... t);

And made it a requirement that the arguments are something that you can use std::get<N> to access the arguments (basically, tuples, pairs, arrays). There would have to be extra checks to verify there isn't a mismatch between the number of arguments given and the number of elements in the tuple.

并要求可以使用std:::get 来访问参数(基本上是元组、对、数组)。必须进行额外的检查,以验证在给定的参数数量和元组中的元素数量之间是否存在不匹配。

Edit: This problem has been bothering me since I read it. And I've created the following class, it is derived from std::tuple, and has no data members, so you can assign it to the tuple and the slicing is harmless. The current version requires that the elements be moveable or copyable, as it creates a temporary and then inserts that into the tuple. If you were a tuple implementer, it should be possible to eliminate even that move.

编辑:自从我读到这篇文章以来,这个问题一直困扰着我。我创建了下面的类,它派生自std::tuple,并且没有数据成员,所以您可以将它分配给tuple,切片是无害的。当前版本要求元素是可移动的或可复制的,因为它创建一个临时的,然后插入到元组中。如果您是一个元组实现者,那么您甚至可以消除这个移动。

namespace detail
{
template<int ... N>
struct index {
    typedef index<N..., sizeof...(N)> next;
};
template<int N>
struct build_index {
    typedef typename build_index<N - 1>::type::next type;
};

template<>
struct build_index<0> {
    typedef index<> type;
};

template<typename T>
struct tuple_index {
    typedef typename build_index<
            std::tuple_size<typename std::remove_reference<T>::type>::value>::type type;

};
}
template<typename ... Elements>
class piecewise_tuple: public std::tuple<Elements...>
{
    typedef std::tuple<Elements...> base_type;

    template<int Index, typename ... Args, int ... N>
    static typename std::tuple_element<Index, base_type>::type 
    construct(std::tuple<Args...>&& args, detail::index<N...>)
    {
        typedef typename std::tuple_element<Index, base_type>::type result_type;
        return result_type(std::get<N>(std::move(args))...);
    }

    template<int ...N, typename ArgTuple>
    piecewise_tuple(detail::index<N...>, ArgTuple&& element_args)
    : base_type( construct<N>( std::get<N>(std::forward<ArgTuple>(element_args)),
                 typename detail::tuple_index< typename std::tuple_element<N, typename std::remove_reference<ArgTuple>::type >::type >::type() )...)
    {

    }

public:

    piecewise_tuple() = default;

    // For non-piecewise constructors, forward them
    template<typename... Args>
    piecewise_tuple(Args&&... args) : base_type(std::forward<Args>(args)...) {}


    template<typename... T>
    piecewise_tuple(std::piecewise_construct_t, T&&... args) :
    piecewise_tuple(typename detail::tuple_index<base_type>::type(),    
                    std::forward_as_tuple(std::forward<T>(args)...))
    {

    }


};

// Usage example
int main()
{
   int i = 5;
   std::unique_ptr<int> up(new int(0));

   piecewise_tuple<std::pair<int, int>, double, std::unique_ptr<int>, int& >
   p(std::piecewise_construct,
    std::forward_as_tuple(1,2),
    std::forward_as_tuple(4.3),
    std::forward_as_tuple(std::move(up)),
    std::forward_as_tuple(i));
   return 0;
}

#3


0  

Here is my implementation of tuple piecewise (it also allow to omit values with omit "keyword"). Zero overhead (no copy/move - direct construction):

下面是我的tuple分段实现(它还允许省略带有省略“关键字”的值)。零开销(无拷贝/移动-直接施工):

http://coliru.stacked-crooked.com/a/6b3f9a5f843362e3

http://coliru.stacked-crooked.com/a/6b3f9a5f843362e3

#include <tuple>
#include <utility>
#include <typeinfo>


struct Omit{} omit;


template <class Field, class ...Fields>
struct TupleHolder{
    using fieldT = Field;
    using nextT = TupleHolder<Fields...>;

    Field field;
    TupleHolder<Fields...> next;

    TupleHolder(){}

    template <class ...ValuesRef>
    TupleHolder(Omit, ValuesRef&& ... values)
            : next( std::forward<ValuesRef>(values)... )
    {}

    template <std::size_t ...ids, class FieldValue, class ...ValuesRef>
    TupleHolder(std::index_sequence<ids...>, FieldValue&& field, ValuesRef&& ... values)
            :
            field( std::get<ids>(std::forward<FieldValue>(field))... ),
            next( std::forward<ValuesRef>(values)... )

    {};


    template <class FieldValue, class ...ValuesRef>
    TupleHolder(FieldValue&& field, ValuesRef&& ... values)
            : TupleHolder(
            std::make_index_sequence<
                    std::tuple_size< std::decay_t<FieldValue> >::value
            >(),
            std::forward<FieldValue>(field),
            std::forward<ValuesRef>(values)...
    )
    {}

};


template <class Field>
struct TupleHolder<Field>{
    using fieldT = Field;
    Field field;    // actually last

    TupleHolder(){}
    TupleHolder(Omit){}

    template <std::size_t ...ids, class FieldValue>
    TupleHolder(std::index_sequence<ids...>, FieldValue&& field)
            :
            field( std::get<ids>(std::forward<FieldValue>(field))... )
    {}


    template <class FieldValue>
    TupleHolder(FieldValue&& field)
            : TupleHolder(
            std::make_index_sequence<
                    std::tuple_size< std::decay_t<FieldValue> >::value
            >(),
            std::forward<FieldValue>(field)
    )
    {}
};



template <int index, int target_index, class T>
struct GetLoop{
    using type = typename T::nextT;

    constexpr static decltype(auto) get(T& data) noexcept{
        return GetLoop<index+1, target_index, typename T::nextT>::get(
                data.next
        );
    }

    constexpr static decltype(auto) get(const T& data) noexcept{
        return GetLoop<index+1, target_index, typename T::nextT>::get(
                data.next
        );
    }


    constexpr static decltype(auto) get(T&& data) noexcept{
        return GetLoop<index+1, target_index, typename T::nextT>::get(
                std::forward<type>(data.next)
        );
    }
};

template <int target_index, class T>
struct GetLoop<target_index, target_index, T>{
    using type = typename T::fieldT;

    constexpr static type& get(T& data) noexcept{
        return data.field;
    }

    constexpr static const type& get(const T& data) noexcept{
        return data.field;
    }

    constexpr static type&& get(T&& data) noexcept{
        return std::forward<type>(data.field);
    }
};


// ----------------------------------------------------------------------------------
//                          F R O N T E N D
// ----------------------------------------------------------------------------------

template<class ...FieldTypes>
struct TuplePiecewise{
    using fieldsT = TupleHolder<FieldTypes...>;
    TupleHolder<FieldTypes...> data;

    TuplePiecewise(){}

   // allow copy constructor
   TuplePiecewise(TuplePiecewise& other)
            : TuplePiecewise(static_cast<const TuplePiecewise&>(other)) {}


    template <class ...ValuesRef>
    explicit constexpr TuplePiecewise(ValuesRef&& ... values) noexcept
            : data( std::forward<ValuesRef>(values)... ){}

    TuplePiecewise( const TuplePiecewise& other ) = default;
    TuplePiecewise( TuplePiecewise&& other ) = default;


    static constexpr const std::size_t size = sizeof...(FieldTypes);
};


template<int index, class ...FieldTypes>
constexpr decltype(auto) get(TuplePiecewise<FieldTypes...> &&list) noexcept {
    return GetLoop<0, index, typename TuplePiecewise<FieldTypes...>::fieldsT >::get(  std::move(list.data) );
}

template<int index, class ...FieldTypes>
constexpr decltype(auto) get(TuplePiecewise<FieldTypes...> &list) noexcept {
    return GetLoop<0, index, typename TuplePiecewise<FieldTypes...>::fieldsT >::get(  list.data );
}

template<int index, class ...FieldTypes>
constexpr decltype(auto) get(const TuplePiecewise<FieldTypes...> &list) noexcept {
    return GetLoop<0, index, typename TuplePiecewise<FieldTypes...>::fieldsT >::get(  list.data );
}

Usage:

用法:

TuplePiecewise< CopyTest, int&, string, int >
list (forward_as_tuple(45,63), forward_as_tuple(i), forward_as_tuple("hghhh"), omit );
decltype(auto) o = get<2>(list);
cout << o;

Tuple inside tuple (zero overhead):

元组内部的元组(零开销):

TuplePiecewise< string, TuplePiecewise<int,int> > list4(forward_as_tuple("RRR"), forward_as_tuple(forward_as_tuple(10), forward_as_tuple(20)));

#1


15  

Question: Why doesn't the same piecewise constructibility exist for arrays and tuples?

问:为什么数组和元组没有同样的分段构造性呢?

My recollection is that piecewise construction was added to std::pair for one reason only: to support uses-allocator construction of the pair elements, i.e. to allow an allocator to be provided and conditionally passed to the elements if they support construction with an allocator (see [allocator.uses] in the standard).

我记得,分段构造被添加到std::pair中,原因只有一个:支持对元素的uses-allocator构建,即允许提供一个分配器,并有条件地传递给支持分配器的元素(参见[allocator])。使用标准)。

At one point during the C++0x process std::pair had twice as many constructors as it does now, with every constructor having a corresponding "allocator-extended" version taking a std::allocator_arg_t and an allocator argument e.g.

在c++ 0x进程std:::pair中有两倍于现在的构造函数,每个构造函数都有一个对应的“allocator-extended”版本,使用std::allocator_arg_t和一个allocator参数,例如。

template<class T, class U>
  struct pair {
    pair();
    pair(allocator_arg_t, const Alloc&);
    template<class TT, class UU>
      pair(TT&&, UU&&);
    template<class Alloc, class TT, class UU>
      pair(allocator_arg_t, const Alloc&, TT&&, UU&&);
    // etc.

There was something of a running joke (haha, only serious) about the insane complexity of std::pair. The support for passing allocators to the elements was removed from std::pair and moved into std::scoped_allocator_adaptor, which is responsible for detecting whether the elements should be constructed with an allocator (see the construct overloads taking a pointer to std::pair in [allocator.adaptor.members]).

关于std:::pair这种疯狂的复杂性,有一个笑话(哈哈,只是认真的)。将分配器传递给元素的支持从std::pair中删除,并转移到std::scoped_allocator_adaptor中,该适配器负责检测是否应该使用分配器构造元素(参见在[allocator.adaptor.members]中使用指向std:::pair的构造重载)。

A nice consequence of the piecewise construction is that you can do "emplace" style initialization of pair elements, allowing pairs of non-movable, non-copyable types, but as far as I know that was not the goal of the design.

分段构造的一个很好的结果是,您可以对成对元素进行“emplace”样式的初始化,允许对不可移动的、不可复制的类型,但据我所知,这并不是设计的目标。

So the reason tuple doesn't support it is that the feature was invented to simplify pair which had ballooned from a very simple type in C++03 to a laughing stock in C++0x, but doing the same for tuple was not considered as important (it was new for C++11 anyway). Also, extending scoped_allocator_adaptor to handle tuples of arbitrary numbers of elements would have made that adaptor much more complicated.

因此,tuple不支持它的原因是,这个特性是为了简化一对,它们从c++ 03中的一个非常简单的类型膨胀到c++ 0x中的一个笑柄,但是对tuple做同样的操作并不重要(它对c++ 11来说是新的)。此外,扩展scoped_allocator_adaptor以处理任意数量的元素元组,会使适配器变得更加复杂。

As for std::array, that's an aggregate type (because reasons) so adding a constructor taking piecewise_construct_t is not possible without making it a non-aggregate.

至于std:::array,这是一个聚合类型(因为原因),所以如果不使它成为非聚合,就不可能添加使用piece ewise_construct_t的构造函数。

#2


12  

I'm not sure why it's not there. Previously, I thought that the implementation wouldn't be possible, given the current varadic template syntax, but I realized that it can be done if it's broken into pieces.

我不知道为什么没有。以前,我认为考虑到当前的可变模板语法,实现是不可能的,但我意识到,如果它被分解为多个部分,那么实现是可以实现的。

If they had defined an interface like this:

如果他们定义了这样的接口:

template<typename... T>
tuple(piecewise_construct, T&&... t);

And made it a requirement that the arguments are something that you can use std::get<N> to access the arguments (basically, tuples, pairs, arrays). There would have to be extra checks to verify there isn't a mismatch between the number of arguments given and the number of elements in the tuple.

并要求可以使用std:::get 来访问参数(基本上是元组、对、数组)。必须进行额外的检查,以验证在给定的参数数量和元组中的元素数量之间是否存在不匹配。

Edit: This problem has been bothering me since I read it. And I've created the following class, it is derived from std::tuple, and has no data members, so you can assign it to the tuple and the slicing is harmless. The current version requires that the elements be moveable or copyable, as it creates a temporary and then inserts that into the tuple. If you were a tuple implementer, it should be possible to eliminate even that move.

编辑:自从我读到这篇文章以来,这个问题一直困扰着我。我创建了下面的类,它派生自std::tuple,并且没有数据成员,所以您可以将它分配给tuple,切片是无害的。当前版本要求元素是可移动的或可复制的,因为它创建一个临时的,然后插入到元组中。如果您是一个元组实现者,那么您甚至可以消除这个移动。

namespace detail
{
template<int ... N>
struct index {
    typedef index<N..., sizeof...(N)> next;
};
template<int N>
struct build_index {
    typedef typename build_index<N - 1>::type::next type;
};

template<>
struct build_index<0> {
    typedef index<> type;
};

template<typename T>
struct tuple_index {
    typedef typename build_index<
            std::tuple_size<typename std::remove_reference<T>::type>::value>::type type;

};
}
template<typename ... Elements>
class piecewise_tuple: public std::tuple<Elements...>
{
    typedef std::tuple<Elements...> base_type;

    template<int Index, typename ... Args, int ... N>
    static typename std::tuple_element<Index, base_type>::type 
    construct(std::tuple<Args...>&& args, detail::index<N...>)
    {
        typedef typename std::tuple_element<Index, base_type>::type result_type;
        return result_type(std::get<N>(std::move(args))...);
    }

    template<int ...N, typename ArgTuple>
    piecewise_tuple(detail::index<N...>, ArgTuple&& element_args)
    : base_type( construct<N>( std::get<N>(std::forward<ArgTuple>(element_args)),
                 typename detail::tuple_index< typename std::tuple_element<N, typename std::remove_reference<ArgTuple>::type >::type >::type() )...)
    {

    }

public:

    piecewise_tuple() = default;

    // For non-piecewise constructors, forward them
    template<typename... Args>
    piecewise_tuple(Args&&... args) : base_type(std::forward<Args>(args)...) {}


    template<typename... T>
    piecewise_tuple(std::piecewise_construct_t, T&&... args) :
    piecewise_tuple(typename detail::tuple_index<base_type>::type(),    
                    std::forward_as_tuple(std::forward<T>(args)...))
    {

    }


};

// Usage example
int main()
{
   int i = 5;
   std::unique_ptr<int> up(new int(0));

   piecewise_tuple<std::pair<int, int>, double, std::unique_ptr<int>, int& >
   p(std::piecewise_construct,
    std::forward_as_tuple(1,2),
    std::forward_as_tuple(4.3),
    std::forward_as_tuple(std::move(up)),
    std::forward_as_tuple(i));
   return 0;
}

#3


0  

Here is my implementation of tuple piecewise (it also allow to omit values with omit "keyword"). Zero overhead (no copy/move - direct construction):

下面是我的tuple分段实现(它还允许省略带有省略“关键字”的值)。零开销(无拷贝/移动-直接施工):

http://coliru.stacked-crooked.com/a/6b3f9a5f843362e3

http://coliru.stacked-crooked.com/a/6b3f9a5f843362e3

#include <tuple>
#include <utility>
#include <typeinfo>


struct Omit{} omit;


template <class Field, class ...Fields>
struct TupleHolder{
    using fieldT = Field;
    using nextT = TupleHolder<Fields...>;

    Field field;
    TupleHolder<Fields...> next;

    TupleHolder(){}

    template <class ...ValuesRef>
    TupleHolder(Omit, ValuesRef&& ... values)
            : next( std::forward<ValuesRef>(values)... )
    {}

    template <std::size_t ...ids, class FieldValue, class ...ValuesRef>
    TupleHolder(std::index_sequence<ids...>, FieldValue&& field, ValuesRef&& ... values)
            :
            field( std::get<ids>(std::forward<FieldValue>(field))... ),
            next( std::forward<ValuesRef>(values)... )

    {};


    template <class FieldValue, class ...ValuesRef>
    TupleHolder(FieldValue&& field, ValuesRef&& ... values)
            : TupleHolder(
            std::make_index_sequence<
                    std::tuple_size< std::decay_t<FieldValue> >::value
            >(),
            std::forward<FieldValue>(field),
            std::forward<ValuesRef>(values)...
    )
    {}

};


template <class Field>
struct TupleHolder<Field>{
    using fieldT = Field;
    Field field;    // actually last

    TupleHolder(){}
    TupleHolder(Omit){}

    template <std::size_t ...ids, class FieldValue>
    TupleHolder(std::index_sequence<ids...>, FieldValue&& field)
            :
            field( std::get<ids>(std::forward<FieldValue>(field))... )
    {}


    template <class FieldValue>
    TupleHolder(FieldValue&& field)
            : TupleHolder(
            std::make_index_sequence<
                    std::tuple_size< std::decay_t<FieldValue> >::value
            >(),
            std::forward<FieldValue>(field)
    )
    {}
};



template <int index, int target_index, class T>
struct GetLoop{
    using type = typename T::nextT;

    constexpr static decltype(auto) get(T& data) noexcept{
        return GetLoop<index+1, target_index, typename T::nextT>::get(
                data.next
        );
    }

    constexpr static decltype(auto) get(const T& data) noexcept{
        return GetLoop<index+1, target_index, typename T::nextT>::get(
                data.next
        );
    }


    constexpr static decltype(auto) get(T&& data) noexcept{
        return GetLoop<index+1, target_index, typename T::nextT>::get(
                std::forward<type>(data.next)
        );
    }
};

template <int target_index, class T>
struct GetLoop<target_index, target_index, T>{
    using type = typename T::fieldT;

    constexpr static type& get(T& data) noexcept{
        return data.field;
    }

    constexpr static const type& get(const T& data) noexcept{
        return data.field;
    }

    constexpr static type&& get(T&& data) noexcept{
        return std::forward<type>(data.field);
    }
};


// ----------------------------------------------------------------------------------
//                          F R O N T E N D
// ----------------------------------------------------------------------------------

template<class ...FieldTypes>
struct TuplePiecewise{
    using fieldsT = TupleHolder<FieldTypes...>;
    TupleHolder<FieldTypes...> data;

    TuplePiecewise(){}

   // allow copy constructor
   TuplePiecewise(TuplePiecewise& other)
            : TuplePiecewise(static_cast<const TuplePiecewise&>(other)) {}


    template <class ...ValuesRef>
    explicit constexpr TuplePiecewise(ValuesRef&& ... values) noexcept
            : data( std::forward<ValuesRef>(values)... ){}

    TuplePiecewise( const TuplePiecewise& other ) = default;
    TuplePiecewise( TuplePiecewise&& other ) = default;


    static constexpr const std::size_t size = sizeof...(FieldTypes);
};


template<int index, class ...FieldTypes>
constexpr decltype(auto) get(TuplePiecewise<FieldTypes...> &&list) noexcept {
    return GetLoop<0, index, typename TuplePiecewise<FieldTypes...>::fieldsT >::get(  std::move(list.data) );
}

template<int index, class ...FieldTypes>
constexpr decltype(auto) get(TuplePiecewise<FieldTypes...> &list) noexcept {
    return GetLoop<0, index, typename TuplePiecewise<FieldTypes...>::fieldsT >::get(  list.data );
}

template<int index, class ...FieldTypes>
constexpr decltype(auto) get(const TuplePiecewise<FieldTypes...> &list) noexcept {
    return GetLoop<0, index, typename TuplePiecewise<FieldTypes...>::fieldsT >::get(  list.data );
}

Usage:

用法:

TuplePiecewise< CopyTest, int&, string, int >
list (forward_as_tuple(45,63), forward_as_tuple(i), forward_as_tuple("hghhh"), omit );
decltype(auto) o = get<2>(list);
cout << o;

Tuple inside tuple (zero overhead):

元组内部的元组(零开销):

TuplePiecewise< string, TuplePiecewise<int,int> > list4(forward_as_tuple("RRR"), forward_as_tuple(forward_as_tuple(10), forward_as_tuple(20)));