[英]How to change the last argument in the parameter pack?
I have a function f1()
我有一个函数
f1()
template <typename... Args>
void f1(Args... args)
{
// the implementation is just an example, I don't really need a complicated
// way to sum numbers
boost::fusion::vector<Args...> v(args...);
std::cout << boost::fusion::accumulate(v, 0, [](auto i1, auto i2) { return i1 + i2; }) << std::endl;
}
I want to call it from a function f2()
, but with a different last argument. 我想从函数
f2()
调用它,但是使用不同的最后一个参数。 Is there a simple approach? 有一个简单的方法吗? I tried a naive one
我尝试了一个天真的
template <typename... Args>
struct CallHelper;
template <>
struct CallHelper<>
{
template <typename... Args>
static void Apply(Args... args) { f1(args...); }
};
template <typename A0>
struct CallHelper<A0>
{
template <typename... Args>
static void Apply(Args ...args, A0 a0)
{
// substitute 10 to the last argument
CallHelper<>::Apply(args..., 10);
}
};
template <typename Head, typename ...TailArgs>
struct CallHelper<Head, TailArgs...>
{
template <typename... Args>
static void Apply(Args... args, Head head, TailArgs ...tailArgs)
{
CallHelper<TailArgs...>::Apply(args..., head, tailArgs...);
}
};
template <typename... Args>
void f2(Args... args)
{
CallHelper<Args...>::Apply(args...);
}
Of course it doesn't work, because Head head
is not the first argument. 当然它不起作用,因为
Head head
不是第一个参数。 Maybe there is a way to make Head head
a parameter pack as well? 也许有一种方法可以让
Head head
成为参数包? Or there is something else I can do? 或者还有其他我可以做的事情?
You might forward your arguments as tuple and then unpack all except the last one using std::integer_sequence
. 您可以将参数转发为元组,然后使用
std::integer_sequence
解压缩除最后一个之外的所有参数。 This code looks much simpler than your approach: 此代码看起来比您的方法简单得多:
template<typename... Args>
void f1(Args... args)
{
boost::fusion::vector<Args...> v(args...);
std::cout << boost::fusion::accumulate(v, 0, [](auto i1, auto i2) { return i1 + i2; }) << std::endl;
}
template<typename Tuple, size_t... idx>
void callImpl(Tuple&& tuple, std::index_sequence<idx...>)
{
f1(std::get<idx>(std::forward<Tuple>(tuple))..., 10);
}
template<typename... Ts>
void callWithLast10(Ts&&... ts)
{
callImpl(std::forward_as_tuple(ts...), std::make_index_sequence<sizeof...(Ts) - 1>());
}
Usage: 用法:
f1(1, 2, 3, 4); // Prints 10
callWithLast10(1, 2, 3, 4); // Prints 16
With the help of index sequences... 在索引序列的帮助下......
#include <utility>
#include <iostream>
template <typename ... Args>
void f1 (Args ... args)
{
using unused=int[];
(void)unused { 0, (std::cout << args << ", ", 0)... };
std::cout << std::endl;
}
template <std::size_t>
struct getVal
{
template <typename T1, typename T2>
T2 operator() (T1 const &, T2 const & t2)
{ return t2; }
};
template <>
struct getVal<0U>
{
template <typename T1, typename T2>
T1 operator() (T1 const & t1, T2 const &)
{ return t1; }
};
template <std::size_t ... Is, typename ... Args>
void f2_helper (std::index_sequence<Is...> const &, Args const & ... args)
{ f1 ( getVal<sizeof...(Is)-Is-1U>()(10, args)... ); }
template <typename ... Args>
void f2 (Args ... args)
{ f2_helper(std::make_index_sequence<sizeof...(Args)>{}, args...); }
int main()
{
f1(1, 2L, 3.3, "ten"); // print 1, 2, 3.3, ten,
f2(1, 2L, 3.3, "ten"); // print 1, 2, 3.3, 10,
}
It's a C++14 solution (require std::index_sequence
and std::make_index_sequence
) but should be simple create substitutes for C++11, if you need they. 它是一个C ++ 14解决方案(需要
std::index_sequence
和std::make_index_sequence
),但如果需要,应该是C ++ 11的简单创建替代品。
Just to post what I mentioned in the comments 只是发表我在评论中提到的内容
#include <utility>
#include <iostream>
template<bool b, typename T1, typename T2>
decltype(auto) replace_if(T1&& t1, T2&& t2)
{
if constexpr(b)
return std::forward<T1>(t1);
else
return std::forward<T2>(t2);
}
template<typename... Args>
void f1(Args&&... args)
{
(std::cout << ... << args) << std::endl;
}
template<typename T, typename... Args, size_t... I>
decltype(auto) replace_last_impl(std::index_sequence<I...>, T&& t, Args&&... args)
{
return f1(replace_if<sizeof...(Args) - 1 == I>(std::forward<T>(t), std::forward<Args>(args))...);
}
template<typename T, typename... Args>
decltype(auto) replace_last(T&& t, Args&&... args)
{
return replace_last_impl(std::index_sequence_for<Args...>{}, std::forward<T>(t), std::forward<Args>(args)...);
}
int main()
{
f1(1, 2, 3); // 123
replace_last("three", 1, 2, 3); // 12three
}
The star of the show is replace_if
, which is a pretty generic way of transforming a parameter pack. show的明星是
replace_if
,这是一种非常通用的转换参数包的方法。
There are easy ways to do it involving writing multiple problem-specific functions just to solve this problem. 有很简单的方法可以解决这个问题,包括编写多个特定于问题的函数。
I don't like that. 我不喜欢那样。
So first I write some helper functions. 所以首先我写一些辅助函数。
nth
takes an index and a bunch of arguments, and returns the nth
one of them: nth
获取一个索引和一堆参数,并返回其中的nth
:
template<std::size_t I, class...Args>
decltype(auto) nth( Args&&... args ) {
return std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...));
}
index_over
and index_upto
let you expand parameter packs of size_t
's inline in your function. index_over
和index_upto
可以在函数中扩展size_t
的内联参数包。 This gets rid of having to create helper functions just to do unpacking: 这摆脱了必须创建帮助函数只是为了解压缩:
template<std::size_t...Is>
auto index_over( std::index_sequence<Is...> ) {
return [](auto&& f)->decltype(auto) {
return decltype(f)(f)( std::integral_constant< std::size_t, I >{} );
};
}
template<std::size_t N>
auto index_upto( std::integral_constant< std::size_t, N > ={} ) {
return index_over( std::make_index_sequence<N>{} );
}
Then, we write our f2
: 然后,我们写了我们的
f2
:
template<class...Args>
void f2( Args&&... args ) {
index_upto< sizeof...(args)-1 >()(
[&](auto...Is) {
f1( nth<Is>(std::forward<Args>(args)...)..., 10 );
}
)
}
and done. 并做了。
This does generate quadradic amounts of unused references, which a good compiler can optimize away but takes time to do that (at compile-time). 这确实生成了四位数量的未使用的引用,一个好的编译器可以优化,但需要时间(在编译时)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.