std :: tuple和标准布局

Nic*_*las 13 c++ language-lawyer c++11

如果所有成员std::tuple都是标准布局类型,那std::tuple本身就是标准布局吗?用户定义的复制构造函数的存在使它变得非常重要,但我想知道它是否仍然是标准布局.

从规范中引用会很好.

Pot*_*ter 9

不,标准布局要求所有非静态数据成员都属于一个基础子对象或直接属于最派生类型,并且std::tuple每个基类实现一个成员的典型实现.

因为成员声明不能是包扩展,根据上述要求,标准布局tuple不能有多个成员.实现仍然可以通过将所有tuple"成员" 存储在一个内部char[]并通过获取对象引用来回避该问题reinterpret_cast.元程序必须生成类布局.必须重新实现特殊成员职能.这将是一个非常痛苦的事情.

  • 典型的实现,是的,但不是_good_实现([根据Howard](http://stackoverflow.com/a/9643480/636019):-P);我怀疑他们_可能_要求标准布局类型的元组只能是标准布局...... (2认同)

Abe*_*ant 5

受PotatoSwatter的回答启发,我致力于为C++ 14创建标准布局元组.

代码实际上有效,但目前不适合使用,因为它涉及未定义的行为.将其视为概念验证. 这是我最终得到的代码:

#include <iostream>
#include <type_traits>
#include <array>
#include <utility>
#include <tuple>

//get_size
template <typename T_head>
constexpr size_t get_size()
{
    return sizeof(T_head);
}

template <typename T_head, typename T_second, typename... T_tail>
constexpr size_t get_size()
{
    return get_size<T_head>() + get_size<T_second, T_tail...>();
}


//concat
template<size_t N1, size_t... I1, size_t N2, size_t... I2>
constexpr std::array<size_t, N1+N2> concat(const std::array<size_t, N1>& a1, const std::array<size_t, N2>& a2, std::index_sequence<I1...>, std::index_sequence<I2...>)
{
  return { a1[I1]..., a2[I2]... };
}

template<size_t N1, size_t N2>
constexpr std::array<size_t, N1+N2> concat(const std::array<size_t, N1>& a1, const std::array<size_t, N2>& a2)
{
    return concat(a1, a2, std::make_index_sequence<N1>{}, std::make_index_sequence<N2>{});
}


//make_index_array
template<size_t T_offset, typename T_head>
constexpr std::array<size_t, 1> make_index_array()
{
    return {T_offset};
}

template<size_t T_offset, typename T_head, typename T_Second, typename... T_tail>
constexpr std::array<size_t, (sizeof...(T_tail) + 2)> make_index_array()
{
    return concat(
        make_index_array<T_offset, T_head>(),
        make_index_array<T_offset + sizeof(T_head),T_Second, T_tail...>()
    );
}

template<typename... T_args>
constexpr std::array<size_t, (sizeof...(T_args))> make_index_array()
{
    return make_index_array<0, T_args...>();
}


template<int N, typename... Ts>
using T_param = typename std::tuple_element<N, std::tuple<Ts...>>::type;


template <typename... T_args>
struct standard_layout_tuple
{
    static constexpr std::array<size_t, sizeof...(T_args)> index_array = make_index_array<T_args...>();

    char storage[get_size<T_args...>()];

    //Initialization
    template<size_t T_index, typename T_val>
    void initialize(T_val&& val)
    {
        void* place = &this->storage[index_array[T_index]];
        new(place) T_val(std::forward<T_val>(val));
    }

    template<size_t T_index, typename T_val, typename T_val2, typename... T_vals_rest>
    void initialize(T_val&& val, T_val2&& val2, T_vals_rest&&... vals_rest)
    {
        initialize<T_index, T_val>(std::forward<T_val>(val));
        initialize<T_index+1, T_val2, T_vals_rest...>(std::forward<T_val2>(val2), std::forward<T_vals_rest>(vals_rest)...);
    }

    void initialize(T_args&&... args)
    {
        initialize<0, T_args...>(std::forward<T_args>(args)...);
    }

    standard_layout_tuple(T_args&&... args)
    {
        initialize(std::forward<T_args>(args)...);
    }

    //Destruction
    template<size_t T_index, typename T_val>
    void destroy()
    {
        T_val* place = reinterpret_cast<T_val*>(&this->storage[index_array[T_index]]);
        place->~T_val();
    }

    template<size_t T_index, typename T_val, typename T_val2, typename... T_vals_rest>
    void destroy()
    {
        destroy<T_index, T_val>();
        destroy<T_index+1, T_val2, T_vals_rest...>();
    }

    void destroy()
    {
        destroy<0, T_args...>();
    }

    ~standard_layout_tuple()
    {
        destroy();
    }

    template<size_t T_index>
    void set(T_param<T_index, T_args...>&& data)
    {
        T_param<T_index, T_args...>* ptr = reinterpret_cast<T_param<T_index, T_args...>*>(&this->storage[index_array[T_index]]);
        *ptr = std::forward<T_param<T_index, T_args...>>(data);
    }

    template<size_t T_index>
    T_param<T_index, T_args...>& get()
    {
        return *reinterpret_cast<T_param<T_index, T_args...>*>(&this->storage[index_array[T_index]]);
    }
};


int main() {
    standard_layout_tuple<float, double, int, double> sltuple{5.5f, 3.4, 7, 1.22};
    sltuple.set<2>(47);

    std::cout << sltuple.get<0>() << std::endl;
    std::cout << sltuple.get<1>() << std::endl;
    std::cout << sltuple.get<2>() << std::endl;
    std::cout << sltuple.get<3>() << std::endl;

    std::cout << "is standard layout:" << std::endl;
    std::cout << std::boolalpha << std::is_standard_layout<standard_layout_tuple<float, double, int, double>>::value << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

实例:https://ideone.com/4LEnSS

有一些我不满意的事情:

这还不适合按原样使用,实际上只是在此状态下将其视为概念验证.我可能会回过头来改进其中的一些问题.或者,如果其他人可以改进它,请随时编辑.