C++11 std::tuple_元素需要深度模板实例化
这里给出了std::tuple_元素的可能实现C++11 std::tuple_元素需要深度模板实例化,c++11,stdtuple,C++11,Stdtuple,这里给出了std::tuple_元素的可能实现 template< std::size_t I, class T > struct tuple_element; // recursive case template< std::size_t I, class Head, class... Tail > struct tuple_element<I, std::tuple<Head, Tail...>> : std::tuple_elem
template< std::size_t I, class T >
struct tuple_element;
// recursive case
template< std::size_t I, class Head, class... Tail >
struct tuple_element<I, std::tuple<Head, Tail...>>
: std::tuple_element<I-1, std::tuple<Tail...>> { };
// base case
template< class Head, class... Tail >
struct tuple_element<0, std::tuple<Head, Tail...>> {
typedef Head type;
};
模板
结构元组元素;
//递归案例
模板<标准::大小\u t I,班长,班级。。。尾部>
结构元组元素
:std::tuple_元素{};
//基本情况
模板<班长,班。。。尾部>
结构元组元素{
头型;
};
但是,如果元组有很多参数(超过100或200个参数),则此实现需要深度递归实例化
问题1:为什么C++11没有添加按索引获取元素的特殊运算符?
像元组[2]或元组[0]
问题2:是否可以减少深度实例化?例如,在D语言中,更多的模板算法(在typetuple中)需要O(log(N))深度实例化
编辑:Q1:为什么C++11没有添加从可变模板按索引获取元素的特殊运算符?
类似于模板std::tuple[2]
应该以某种方式解析为typenamestd::string
,那么这意味着您现在需要解释为什么这样做。同样,元组是一种库特性,而不是一种语言构造。因此,必须有某种语言构造,typename[integer]
是有效的构造。那会是什么?这意味着什么
如果你的意思是:
std::tuple<int, float, std::string> tpl{...};
std::tuple tpl{…};
我们应该能够通过tpl[2]
获得字符串,这是“不可能发生”的几个阴影。C++是一种静态类型语言。std::get
能够不受影响的唯一原因是整数索引不是函数参数;它是一个模板参数。这就是允许std::get
返回与std::get
完全不同的类型的原因。这在操作符[](int)
中是不可能发生的;该函数必须始终返回相同的类型
所以现在你需要像template。。。操作员[]()
。这将非常令人困惑,因为您不能再对该类型执行tpl[runtimeValue]
(因为模板参数必须是编译时值)。没有限制运算符[]
处理运行时值的类型。所以你会创造一个非常古怪的类型
即使这样。。。它仍然需要进行递归才能得到值
是否可以减少深度实例化
在编译时间之外(这不是一个不合理的问题),它有什么关系?一条像样的内联线会把它们大部分扔掉
至于编译时间,std::tuple
有各种各样的特性。他们是否能够以非递归的方式执行tuple\u元素
,我不这么认为。似乎表明,尽管以非递归方式实现了元组本身
为什么C++11没有添加按索引获取元素的特殊运算符?像元组还是元组[0]
首先,因为即使他们这样做了,它仍然以同样的方式工作:使用递归。元组主要是一种库特性。尽管它们利用了诸如可变模板之类的语言特性,但在C++98/03中它们或多或少都是功能性的
其次,这是不可能的。没有一个非常困难的语言变化
不清楚您所说的元组[2]是什么意思
如果您的意思是std::tuple[2]
应该以某种方式解析为typenamestd::string
,那么这意味着您现在需要解释为什么这样做。同样,元组是一种库特性,而不是一种语言构造。因此,必须有某种语言构造,typename[integer]
是有效的构造。那会是什么?这意味着什么
如果你的意思是:
std::tuple<int, float, std::string> tpl{...};
std::tuple tpl{…};
我们应该能够通过tpl[2]
获得字符串,这是“不可能发生”的几个阴影。C++是一种静态类型语言。std::get
能够不受影响的唯一原因是整数索引不是函数参数;它是一个模板参数。这就是允许std::get
返回与std::get
完全不同的类型的原因。这在操作符[](int)
中是不可能发生的;该函数必须始终返回相同的类型
所以现在你需要像template。。。操作员[]()
。这将非常令人困惑,因为您不能再对该类型执行tpl[runtimeValue]
(因为模板参数必须是编译时值)。没有限制运算符[]
处理运行时值的类型。所以你会创造一个非常古怪的类型
即使这样。。。它仍然需要进行递归才能得到值
是否可以减少深度实例化
在编译时间之外(这不是一个不合理的问题),它有什么关系?一条像样的内联线会把它们大部分扔掉
至于编译时间,
std::tuple
有各种各样的特性。他们是否能够以非递归的方式执行tuple\u元素
,我不这么认为。似乎表明,尽管以非递归方式实现了元组
本身。我认为这个实现有O(log(N))实例化深度;O(log(N))索引技巧(修改为使用std::size\u t
而不是u
namespace detail
{
template<std::size_t>
struct Any
{
Any(...) {}
};
template<typename T>
struct wrapper { using type = T; };
template<std::size_t... Is>
struct get_nth_helper
{
template<typename T>
static auto deduce(Any<Is>..., wrapper<T>, ...) -> wrapper<T>;
};
template<std::size_t... Is, typename... Ts>
auto deduce_seq(seq<Is...>, wrapper<Ts>... pp)
-> decltype( get_nth_helper<Is...>::deduce(pp...) );
}
#include <tuple>
template<std::size_t n, class Tuple>
struct tuple_element;
template<std::size_t n, class... Ts>
struct tuple_element<n, std::tuple<Ts...>>
{
using wrapped_type = decltype( detail::deduce_seq(gen_seq<n>{},
detail::wrapper<Ts>()...) );
using type = typename wrapped_type::type;
};
#include <typeinfo>
#include <iostream>
int main()
{
std::tuple<int, double, bool, char> t;
tuple_element<1, decltype(t)>::type x;
std::cout << typeid(x).name() << std::endl;
}
#include <tuple>
namespace detail
{
template < std::size_t Index, class Arg >
struct s_get_one
{
// declare a function that links an Index with an Arg type
friend Arg get(s_get_one, std::integral_constant<std::size_t, Index>);
};
template < typename... Bases >
struct s_get : Bases... {};
}
template < std::size_t I, class T >
struct tuple_element;
template < std::size_t I, class... Args >
struct tuple_element < I, std::tuple<Args...> >
{
template<class T>
struct wrapper { using type = T; };
// deduce indices from seq helper
template < std::size_t... Is >
static auto helper(seq<Is...>)
-> detail::s_get< detail::s_get_one<Is, wrapper<Args>>... >;
// generate indices in O(log(N)) and use name lookup to find the type
using IC = std::integral_constant<std::size_t, I>;
using wrapped_type = decltype( get(helper(gen_seq<sizeof...(Args)>{}), IC{}) );
using type = typename wrapped_type::type;
};
template< int ...i> struct seq{};
// GCC couldn't optimize sizeof..(i) ,
//see http://stackoverflow.com/questions/19783205/why-sizeof-t-so-slow-implement-c14-make-index-sequence-without-sizeof
//so I use direct variable `s` instead of it.
// i.e. s == number of variadic arguments in `I`.
template< int s, typename I, typename J > struct concate;
template< int s, int ...i, int ...j>
struct concate<s, seq<i...>, seq<j...> >
{
typedef seq<i..., (s + j)...> type;
};
template<int n> struct make_seq_impl;
template< int n> using make_seq = typename make_seq_impl<n>::type;
template<> struct make_seq_impl<0>{ typedef seq<> type;};
template<> struct make_seq_impl<1>{ typedef seq<0> type;};
template<int n> struct make_seq_impl: concate< n/2, make_seq<n/2>, make_seq<n-n/2>>{};
template< typename ...T> using seq_for = make_seq< sizeof...(T) > ;
//----------------------------------
template< int i, typename T> struct id{};
template< typename T> struct id<0,T>{ typedef T type;};
template< typename ...T> struct base : T ... {};
template< typename ...T> struct tuple{};
template< std::size_t i, typename Tuple> struct tuple_element;
template< std::size_t i, typename ...T>
struct tuple_element< i, tuple<T...> >
{
template< typename Seq > struct apply;
template< int ...j > struct apply< seq<j...> >
{
// j xor i ==> ( 0 xor i), (1 xor i), (2 xor i ),...(i xor i) ...
// => i0, i1, ..., 0 (at pos i) ...
// and only id<0,T> has `type`.
typedef base< id< (j xor i), T> ... > base_t;
typedef typename base_t::type type;
};
typedef typename apply< seq_for<T...> >::type type;
};