为什么没有分段元组构造?

Ker*_* SB 40 c++ tuples piecewise c++11

该标准模板std::pairstd::array有特殊情况std::tuple,它按理说,他们应该有一个非常类似的功能集.

然而,三者中唯一的,std::pair允许分段构造.也就是说,如果该类型T1T2可以从一组参数来构建a1, a2, ...b1, b2, ...,然后讲道德,我们可以做一对

"pair<T1, T2> p(a1, a2, ..., b1, b2, ...)"
Run Code Online (Sandbox Code Playgroud)

直.实际上,这是拼写为这样的:

std::pair<T1, T2> p(std::piecewise_construct,
                    std::forward_as_tuple(a1, a2, ...),
                    std::forward_as_tuple(b1, b2, ...));
Run Code Online (Sandbox Code Playgroud)

问题:为什么阵列和元组不存在相同的分段构造性?有一个深刻的原因,还是一个普通的遗漏?例如,拥有以下内容会很高兴:

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, ...));
Run Code Online (Sandbox Code Playgroud)

有没有理由不能这样做?[ 编辑:或者我是否完全误解了分段建设的目的?]

(我确实有一种情况,我希望初始化一个带有默认元素值的元组向量,我宁愿直接从参数构造,而不是再次拼写出每个元组元素类型.)

Jon*_*ely 16

问题:为什么阵列和元组不存在相同的分段构造性?

我的回忆是,std::pair仅仅由于一个原因添加了分段构造:支持对元素的use-allocator构造,即,如果它们支持使用分配器构造,则允许提供分配器并有条件地传递给元素(参见[allocator] .uses]在标准中).

在C++ 0x进程期间的某个时刻,std::pair构造函数的数量是现在的两倍,每个构造函数都有一个相应的"allocator-extended"版本,它带有一个std::allocator_arg_t和一个分配器参数,例如

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.
Run Code Online (Sandbox Code Playgroud)

关于疯狂的复杂性,有一个流行的笑话(哈哈,只有严肃)std::pair.将分配器传递给元素的支持被移除std::pair并移入std::scoped_allocator_adaptor,它负责检测是否应该使用分配器构造元素(请参阅在[allocator.adaptor.members]中construct获取指针的重载std::pair).

分段建设的一个很好的结果是,你可以做对元素"布设"风格的初始化,允许对不可移动,不可复制的类型,但据我所知,这不是设计的目标.

所以有理由tuple不支持它的是,该功能的发明是为了简化pair其已经从C++ 03到C++ 0x中的笑柄一个非常简单的类型激增,但这样做同样为tuple不被认为是重要的(无论如何,这对C++ 11来说是新的).此外,扩展scoped_allocator_adaptor以处理任意数量的元素的元组会使该适配器变得更加复杂.

至于std::array,这是一种聚合类型(因为原因),因此piecewise_construct_t如果不将其作为非聚合,则无法添加构造函数.


Dav*_*e S 12

我不确定为什么它不存在.以前,我认为在给定当前的varadic模板语法的情况下实现是不可能的,但我意识到如果它被分成几部分就可以完成.

如果他们定义了这样的界面:

template<typename... T>
tuple(piecewise_construct, T&&... t);
Run Code Online (Sandbox Code Playgroud)

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

编辑:这个问题一直困扰着我,因为我读了它.我创建了以下类,它是派生自的std::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;
}
Run Code Online (Sandbox Code Playgroud)