调用每个可变参数模板参数和数组的函数 [英] Calling a function for each variadic template argument and an array
问题描述
所以我有一些类型 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));
}
如果您可以更改 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));
}
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);
}
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);
}
这篇关于调用每个可变参数模板参数和数组的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!