调用每个可变参数模板参数和数组的函数 [英] Calling a function for each variadic template argument and an array

查看:204
本文介绍了调用每个可变参数模板参数和数组的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一些类型 X

  typedef .. 。 X; 

和模板函数 f



  class< typename T> 
void f(X& x_out,const T& arg_in);

然后函数 g



  void g(const X * x_array,size_t x_array_size); 

我需要写一个可变参数模板函数 h 这样做:

 模板< typename ... Args> 
void h(Args ... args)
{
constexpr size_t nargs = sizeof ...(args); // get number of args
X x_array [nargs]; //创建该大小的X数组

for(int i = 0; i f(x_array [i],args [i]); // call f(does not work)

g(x_array,nargs); // call g with x_array
}

它不工作的原因是因为你



替换 h 的中间部分的最佳方法是什么? ?



获胜者是Xeo:

  template< class T> X fv(const T& t){X x; f(x,t); return x; } 

template< class ... Args>
void h(Args ... args)
{
X x_array [] = {fv(args)...};

g(x_array,sizeof ...(Args));
}

(实际上在我的具体情况下,我可以重写f,因此我甚至不需要上面的fv)

解决方案

你可以重构或换行 f 返回一个新的 X ,而不是通过它,因为这将播放包扩展到手,使函数真的简洁:

 模板< class T> 
X fw(T const& t){X x; f(x,t); return x; }

template< class ... Args>
void h(Args ... args){
X xs [] = {fw(args)...};
g(xs,sizeof ...(Args));
}

Live example。



如果您可以更改 g ,只接受 std :: initializer_list ,它会更简洁:

  template< class。 Args> 
void h(Args ... args){
g({f(args)...});
}

或者(或许更好),你也可以提供一个包装器 g ,转发到真实的 g

  void g(X const *,unsigned){} 

g(std :: initializer_list< X> const& xs){g(xs.begin(),xs.size()); }

template< class ... Args>
void h(Args ... args){
g({f(args)...});
}

现场示例。

修改:另一个选项是使用临时数组:

  template< class T> 
使用Alias = T;

template< class T>
T& as_lvalue(T& v){return v; }

template< class ... Args>
void h(Args ... args){
g(as_lvalue(Alias {f(args)...}),sizeof ...(Args));
}

Live example。请注意, as_lvalue 函数很危险,数组仍然只生存到完整表达式的结尾(在这种情况下 g ),因此在使用时要谨慎。需要 Alias ,因为由于语言语法,不允许使用 X [] {...} / p>

如果所有这些都不可能,您需要递归访问 args 包的所有元素。 p>

  #include< tuple> 

模板< unsigned> struct uint_ {}; //iteration的编译时整数

template< unsigned N,class Tuple>
void h_helper(X(&)[N],Tuple const& uint_ N){}

模板<无符号N,类Tuple,无符号I = 0&
void h_helper(X(& xs)[N],Tuple const& args,uint_< I> = {}){
f(xs [1],std :: get& ));
h_helper(xs,args,uint_< I + 1>());
}

template< typename ... Args>
void h(Args ... args)
{
static constexpr unsigned nargs = sizeof ...(Args);
X xs [nargs];

h_helper(xs,std :: tie(args ...));

g(xs,nargs);
}

实例



编辑:受ecatmur注释启发,我使用了指导手法,使其只用于扩展包,并使用 f 和<$ c $

 模板< unsigned ... Indices> 
struct indices {
using next = indices< Indices ...,sizeof ...(Indices)> ;;
};
template< unsigned N>
struct build_indices {
using type = typename build_indices< N-1> :: type :: next;
};
模板<>
struct build_indices< 0> {
using type = indices<> ;;
};
template< unsigned N>
使用IndicesFor = typename build_indices< N> :: type;

template< unsigned N,unsigned ... is,class ... Args>
void f_them_all(X(& xs)[N],indices< Is ...>,Args ... args){
int unused [] = {(f ,args),1)...};
(void)unused;
}

template< class ... Args>
void h(Args ... args){
static constexpr unsigned nargs = sizeof ...(Args);
X xs [nargs];
f_them_all(xs,IndicesFor< nargs>(),args ...);
g(xs,nargs);
}

实例


So I have some type X:

typedef ... X;

and a template function f:

class <typename T>
void f(X& x_out, const T& arg_in);

and then a function g:

void g(const X* x_array, size_t x_array_size);

I need to write a variadic template function h that does this:

template<typename... Args>
void h(Args... args)
{
    constexpr size_t nargs = sizeof...(args); // get number of args
    X x_array[nargs]; // create X array of that size

    for (int i = 0; i < nargs; i++) // foreach arg
        f(x_array[i], args[i]); // call f (doesn't work)

    g(x_array, nargs); // call g with x_array
}

The reason it doesn't work is because you can't subscript args like that at runtime.

What is the best technique to replace the middle part of h?

And the winner is Xeo:

template<class T> X fv(const T& t) { X x; f(x,t); return x; }

template<class... Args>
void h(Args... args)
{
  X x_array[] = { fv(args)... };

  g(x_array, sizeof...(Args));
}

(Actually in my specific case I can rewrite f to return x by value rather than as an out parameter, so I don't even need fv above)

解决方案

You could refactor or wrap f to return a new X instead of having it passed, since this would play pack expansion into the hand and make the function really concise:

template<class T>
X fw(T const& t){ X x; f(x, t); return x; }

template<class... Args>
void h(Args... args){
  X xs[] = { fw(args)... };
  g(xs, sizeof...(Args));
}

Live example.

And if you could change g to just accept an std::initializer_list, it would get even more concise:

template<class... Args>
void h(Args... args){
  g({f(args)...});
}

Live example. Or (maybe better), you could also provide just a wrapper g that forwards to the real g:

void g(X const*, unsigned){}

void g(std::initializer_list<X> const& xs){ g(xs.begin(), xs.size()); }

template<class... Args>
void h(Args... args){
  g({f(args)...});
}

Live example.
Edit: Another option is using a temporary array:

template<class T>
using Alias = T;

template<class T>
T& as_lvalue(T&& v){ return v; }

template<class... Args>
void h(Args... args){
  g(as_lvalue(Alias<X[]>{f(args)...}), sizeof...(Args));
}

Live example. Note that the as_lvalue function is dangerous, the array still only lives until the end of the full expression (in this case g), so be cautious when using it. The Alias is needed since just X[]{ ... } is not allowed due to the language grammar.

If all of that's not possible, you'll need recursion to access all elements of the args pack.

#include <tuple>

template<unsigned> struct uint_{}; // compile-time integer for "iteration"

template<unsigned N, class Tuple>
void h_helper(X (&)[N], Tuple const&, uint_<N>){}

template<unsigned N, class Tuple, unsigned I = 0>
void h_helper(X (&xs)[N], Tuple const& args, uint_<I> = {}){
  f(xs[I], std::get<I>(args));
  h_helper(xs, args, uint_<I+1>());
}

template<typename... Args>
void h(Args... args)
{
    static constexpr unsigned nargs = sizeof...(Args);
    X xs[nargs];

    h_helper(xs, std::tie(args...));

    g(xs, nargs);
}

Live example.

Edit: Inspired by ecatmur's comment, I employed the indices trick to make it work with just pack expansion and with f and g as-is, without altering them.

template<unsigned... Indices>
struct indices{
  using next = indices<Indices..., sizeof...(Indices)>;
};
template<unsigned N>
struct build_indices{
  using type = typename build_indices<N-1>::type::next;
};
template <>
struct build_indices<0>{
  using type = indices<>;
};
template<unsigned N>
using IndicesFor = typename build_indices<N>::type;

template<unsigned N, unsigned... Is, class... Args>
void f_them_all(X (&xs)[N], indices<Is...>, Args... args){
  int unused[] = {(f(xs[Is], args), 1)...};
  (void)unused;
}

template<class... Args>
void h(Args... args){
  static constexpr unsigned nargs = sizeof...(Args);
  X xs[nargs];
  f_them_all(xs, IndicesFor<nargs>(), args...);
  g(xs, nargs);
}

Live example.

这篇关于调用每个可变参数模板参数和数组的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆