Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板参数包访问第n个类型和第n个元素_C++_C++11_Variadic Templates - Fatal编程技术网

C++ 模板参数包访问第n个类型和第n个元素

C++ 模板参数包访问第n个类型和第n个元素,c++,c++11,variadic-templates,C++,C++11,Variadic Templates,下面的文章是我发现的第一个模板参数包方案 在第16页,它讨论了引入两个新操作符[]和访问参数包元素和参数包类型 此类运算符的建议语法包括两个新运算符:[]用于访问值和。访问类型。例如: template<int N, typename Tuple> struct tuple_element; template<int N, ... Elements> struct tuple_element<tuple<Elements...> > {

下面的文章是我发现的第一个模板参数包方案

在第16页,它讨论了引入两个新操作符[]和访问参数包元素和参数包类型

此类运算符的建议语法包括两个新运算符:[]用于访问值和。访问类型。例如:

template<int N, typename Tuple> struct tuple_element;
template<int N, ... Elements>
struct tuple_element<tuple<Elements...> >
{
    typedef Elements.<N> type;
};

template<int N, ... Elements>
Elements.<N>& get(tuple<Elements...>& t)
{ return t.[N]; }

template<int N, ... Elements>
const Elements.<N>& get(const tuple<Elements...>& t)
{ return t.[N]; }
模板结构元组元素;
模板
结构元组元素
{
typedef元素。类型;
};
模板
元素和获取(元组和t)
{返回t[N];}
模板
常量元素和get(常量元组和t)
{返回t[N];}

那么这些运营商在哪里?如果没有,它们的替换对象是什么?

C++11没有相应的运算符,这就是它们被提出的原因。使用C++11,您需要自己提取相应的信息,或者使用已经执行必要操作的类。最简单的方法可能只是使用已经实现了相应逻辑的
std::tuple

如果您想知道
std::tuple
目前是如何实现这些操作的:它基本上是函数编程中使用相当糟糕的函数编程符号的一种练习。一旦您知道如何获取序列的
n
-th类型,使用从索引和类型上参数化的基类继承来获取
n
-th元素就相当简单了。实现类似于
tuple\u元素
的东西可能看起来像这样:

template <int N, typename... T>
struct tuple_element;

template <typename T0, typename... T>
struct tuple_element<0, T0, T...> {
    typedef T0 type;
};
template <int N, typename T0, typename... T>
struct tuple_element<N, T0, T...> {
    typedef typename tuple_element<N-1, T...>::type type;
};
模板
结构元组元素;
模板
结构元组元素{
T0型;
};
模板
结构元组元素{
typedef typename元组元素::type type;
};
在实现像
std::tuple
这样的东西时,实际更具挑战性的一点是变出一个索引列表,这样您就得到了一个类型和整数的并行列表,然后可以对其进行扩展,例如,使用(内部细节的具体外观将有所不同,但类型及其索引的并行参数包的基本思想将以某种方式存在):

模板
类元组库:
公共元组字段{
};

其他人已经回答说可以通过
std::tuple
完成。如果您想访问第n种类型的参数包,您可能会发现以下元函数非常方便:

template<int N, typename... Ts> using NthTypeOf =
        typename std::tuple_element<N, std::tuple<Ts...>>::type;
使用NthTypeOf的模板=
typename std::tuple_元素::type;
用法:

using ThirdType = NthTypeOf<2, Ts...>;
使用ThirdType=NthTypeOf;
要从包中获取第n个元素,您可以编写: 选择1 使用tuple_元素获取第n个元素的返回类型:

template<size_t index, typename T, typename... Ts>
inline constexpr typename enable_if<index==0, T>::type
get(T&& t, Ts&&... ts) {
    return t;
}

template<size_t index, typename T, typename... Ts>
inline constexpr typename enable_if<(index > 0) && index <= sizeof...(Ts),
          typename tuple_element<index, tuple<T, Ts...>>::type>::type
get(T&& t, Ts&&... ts) {
    return get<index-1>(std::forward<Ts>(ts)...);
}

// below is optional - just for getting a more readable compilation error
// in case calling get with a bad index

inline template<long long index, typename... Ts>
constexpr bool index_ok() {
    return index >= 0 && index < sizeof...(Ts);
}

template<long long index, typename T, typename... Ts>
inline constexpr
typename enable_if<!index_ok<index, T, Ts...>(), T>::type
get(T&& t, Ts&&... ts) {
    static_assert(index_ok<index, T, Ts...>(),
        "bad index in call to get, smaller than zero or above pack size");
    return t;
}
模板
内联constexpr typename启用\u if::type
获取(T&&T,Ts&&T…Ts){
返回t;
}
模板
内联constexpr typename启用(如果为0)&&index::type
获取(T&&T,Ts&&T…Ts){
返回get(std::forward(ts)…);
}
//下面是可选的-只是为了获得更可读的编译错误
//如果使用错误的索引调用get
内联模板
constexpr bool index_ok(){
返回索引>=0&&index::type
获取(T&&T,Ts&&T…Ts){
静态断言(索引确定(),
“调用获取时索引错误,小于零或大于包大小”);
返回t;
}
选择2 在不使用元组的情况下,依赖于自动返回类型,特别是C++14 decltype(auto),以及使用enable_if作为模板参数而不是返回类型:

template<size_t index, typename T, typename... Ts,
    typename enable_if<index==0>::type* = nullptr>
inline constexpr decltype(auto) get(T&& t, Ts&&... ts) {
    return std::forward<T>(t); 
}

template<size_t index, typename T, typename... Ts,
    typename enable_if<(index > 0 && index <= sizeof...(Ts))>::type* = nullptr>
inline constexpr decltype(auto) get(T&& t, Ts&&... ts) {
    return get<index-1>(std::forward<Ts>(ts)...);
}

template<long long index, typename... Ts>
inline constexpr bool index_ok() {
    return index >= 0 && index < (long long)sizeof...(Ts);
}

// block (compilation error) the call to get with bad index,
// providing a readable compilation error
template<long long index, typename T, typename... Ts,
    typename enable_if<(!index_ok<index, T, Ts...>())>::type* = nullptr>
inline constexpr decltype(auto) get(T&& t, Ts&&... ts) {
    static_assert(index_ok<index, T, Ts...>(),
        "bad index in call to get, smaller than zero or above pack size");
    return std::forward<T>(t); // need to return something...
                               // we hope to fail on the static_assert above
}
模板
内联constexpr decltype(自动)获取(T&&T、Ts&&T、Ts){
返回std::向前(t);
}
模板
内联constexpr decltype(自动)获取(T&&T、Ts&&T、Ts){
返回get(std::forward(ts)…);
}
模板
内联constexpr bool index_ok(){
返回索引>=0&&index<(长-长)大小…(Ts);
}
//阻止(编译错误)使用错误索引调用get,
//提供可读的编译错误
模板
内联constexpr decltype(自动)获取(T&&T、Ts&&T、Ts){
静态断言(索引确定(),
“调用获取时索引错误,小于零或大于包大小”);
return std::forward(t);//需要返回某些内容。。。
//我们希望在上述静态问题上失败
}
用法示例:
模板
无效重置元素n(Ts&&…Ts){
get(std::forward(ts)…={};//假设元素N有一个空的ctor
}
int main(){
int i=0;
字符串s=“hello”;
get(i,2,“hello”,“hello”s,'a')+=get(2);
get(1,i,“你好”,4)+=get(1,2);
get(1,2,“hello”,i)+=get(0,1,2);
get(1,2,s,4)=get(0,1,“hi”);

cout我们可以实现一个简单的函数来直接获取第n个参数,无需任何递归调用,只需在编译时执行许多纯类型操作。 让我们先看看关键代码:

template<class...Ts>
struct GetImp {
  template<class T, class...Us>
  static decltype(auto) impl(Ts&&..., T&& obj, Us&&...) {
    return std::forward<T>(obj);
  }
};

template<size_t n, class...Ts>
decltype(auto) get(Ts&&...args) {
  static_assert(n<sizeof...(args), "index over range");
  return Transform<GetImp, Before_s<n, Seq<Ts...>> >
    ::impl(std::forward<Ts>(args)...);
}
编辑:高级实施

#define OMIT_T(...) typename __VA_ARGS__::type

template<class...Args>
struct Seq { };

template< template<class...> class Dst >
struct TransformImp{
    template< template<class...>class Src, class...Args >
    static Dst<Args...> from(Src<Args...>&&);
};
template< template<class...> class Dst, class T>
using Transform = decltype(TransformImp<Dst>::from(std::declval<T>()));
template<class T>
using Seqfy = Transform<Seq, T>;


template<class...>struct MergeImp;
template<class...Ts, class...Others>
struct MergeImp<Seq<Ts...>, Seq<Others...>>
{
  using type = Seq<Ts..., Others...>;
};
template<class first, class second>
using Merge = OMIT_T(MergeImp<Seqfy<first>, Seqfy<second> >);
template<class T, class U>
using Merge_s = OMIT_T(MergeImp<T, U>);

template<size_t, class...>struct BeforeImp;

template<size_t n, class T, class...Ts>
struct BeforeImp<n, Seq<T, Ts...>> {
    static_assert(n <= sizeof...(Ts)+1, "index over range");
    using type = Merge_s<Seq<T>, OMIT_T(BeforeImp<n - 1, Seq<Ts...>>)>;
};

template<class T, class...Ts>
struct BeforeImp<1, Seq<T, Ts...>> {
    using type = Seq<T>;
};
template<class T, class...Ts>
struct BeforeImp<0, Seq<T, Ts...>> {
    using type = Seq<>;
};
template<size_t n>
struct BeforeImp<n, Seq<>> {
    using type = Seq<>;
};

template<size_t n, class T>
using Before = OMIT_T(BeforeImp<n, Seqfy<T>>);
template<size_t n, class T>
using Before_s = OMIT_T(BeforeImp<n, T>);
我们不需要使用Before_s来计算n-1类型,而是在第n类型之前, 我们可以忽略它们:

struct EatParam{
    constexpr EatParam(...)noexcept{}
};

template<size_t n>
struct GenSeqImp {
  using type = Merge_s<OMIT_T(GenSeqImp<n / 2>), OMIT_T(GenSeqImp<n - n / 2>)>;
};
template<>
struct GenSeqImp<0> {
  using type = Seq<>;
};
template<>
struct GenSeqImp<1> {
  using type = Seq<EatParam>;
};

template<size_t n>
using GenSeq = OMIT_T(GenSeqImp<n>);


template<class...Ts>
struct GetImp {
  template<class T>
  static constexpr decltype(auto) impl(Ts&&..., T&& obj, ...)noexcept {
    return std::forward<T>(obj);
  }
};


template<size_t n, class...Ts>
constexpr decltype(auto) get(Ts&&...args)noexcept {
  static_assert(n<sizeof...(args), "index over range.");
  //return Transform<GetImp, Before_s<n, Seq<Ts...>> >
  return Transform<GetImp, GenSeq<n>>
    ::impl(std::forward<Ts>(args)...);
}
struct-EatParam{
constexpr EatParam(…)noexcept{}
};
模板
结构GenSeqImp{
使用类型=合并;
};
模板
结构GenSeqImp{
使用类型=Seq;
};
模板
结构GenSeqImp{
使用类型=Seq;
};
模板
使用GenSeq=省略(GenSeqImp);
模板
结构GetImp{
模板
静态constexpr decltype(自动)impl(Ts&&…,T&&obj…)无异常{
返回标准::转发(obj);
}
};
模板
constexpr decltype(自动)get(Ts&…args)noexcept{

静态断言(n访问第n个元素?

使用
std::forward\u as\u tuple

template <int I, class... Ts>
decltype(auto) get(Ts&&... ts) {
  return std::get<I>(std::forward_as_tuple(ts...));
}
模板
decltype(自动)获取(Ts&&…Ts){
返回std::get(std::forward_as_tuple(ts…);
}
用法示例:

template<class...Ts>
void foo(Ts&&...ts){

  auto& first = get<0>(ts...);
  auto second = get<1>(ts...);

  first = 'H';
  second = 'E';

  (std::cout << ... << ts);
}

foo('h','e','l','l','o');
// prints "Hello"
模板
无效foo(Ts&…Ts){
自动&首先=获取(ts…);
自动秒=获取(ts…);
第一个='H';
第二个='E';

(std::cout)它们的替代品可能是将参数包放入
std::tuple
并使用and,and是递归实现的。另请参见@DyP:
std::gettemplate <int I, class... Ts>
decltype(auto) get(Ts&&... ts) {
  return std::get<I>(std::forward_as_tuple(ts...));
}
template<class...Ts>
void foo(Ts&&...ts){

  auto& first = get<0>(ts...);
  auto second = get<1>(ts...);

  first = 'H';
  second = 'E';

  (std::cout << ... << ts);
}

foo('h','e','l','l','o');
// prints "Hello"