問題描述
所以我有一些類型 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
來做到這一點:
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.
替換h
中間部分的最佳技術是什么?
What is the best technique to replace the middle part of 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 以按值而不是作為輸出參數返回 x,所以我什至不需要上面的 fv)
(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)
推薦答案
你可以重構或包裝 f
以返回一個新的 X
而不是讓它通過,因為這會玩包擴展到手,使功能真正簡潔:
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));
}
現場示例.
如果您可以將 g
更改為僅接受 std::initializer_list
,它會變得更加簡潔:
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)...});
}
現場示例.或者(也許更好),您也可以僅提供一個包裝器 g
轉發到真正的g
:
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.
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));
}
現場示例. 請注意,as_lvalue
函數是危險的,數組仍然只存在到完整表達式的結尾(在本例中為 g
),所以在使用它時要小心.Alias
是必需的,因為語言語法不允許 X[]{ ... }
.
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.
如果這一切都不可能,您將需要遞歸訪問 args
包的所有元素.
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);
}
現場示例.
受 ecatmur 評論的啟發,我采用了索引技巧使其僅通過包擴展和 f
和 g
原樣工作,而無需更改它們.
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);
}
現場示例.
這篇關于為每個可變參數模板參數和數組調用一個函數的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!