使用可变参数调用后续方法
Use variadic args to call subsequent method
假设我有接受 1 个可调用 F 和可变参数列表的函数:
template <class F, class ...Args>
void combine(F& f, Args&& ... args)
F
可以有从 1 到 sizeof...(Args)
的任意数量的参数。所以我需要使用 c++17 来调用 F
,然后将未使用的参数放入 std::cout
,就像那样
{
std::invoke(f, [some way to restrict args]);
std::cout << [The rest of args] << "\n";
}
最大的问题是检测 F
的参数数量。
正如 Igor Tandetnik 在评论中指出的那样,这通常是不可能的,因为 f
函数可以是可变的,可以是具有模板 operator()
的 lambda 或实例一个 class/struct 和多个 operator()
.
无论如何...在某些情况下,您可以使用以下内容检测参数的数量
template <typename T>
struct num_args
: public num_args<decltype(&T::operator())>
{ };
template <typename R, typename ... Args>
struct num_args<R(*)(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
// other specialization follows
此时,您可以编写 combine()
来调用具有适当索引和参数元组的辅助函数
template <typename F, typename ... Args>
void combine (F & func, Args && ... as)
{
constexpr auto n1 { num_args<F>::value };
constexpr auto n2 { sizeof...(Args) - n1 };
combine_helper(std::make_index_sequence<n1>{},
std::make_index_sequence<n2>{},
func,
std::forward_as_tuple(std::forward<Args>(as)...));
}
辅助函数可以简单如下
template <std::size_t ... Is1, std::size_t ... Is2, typename F, typename T>
void combine_helper (std::index_sequence<Is1...>,
std::index_sequence<Is2...>,
F & func, T && t)
{
func(std::get<Is1>(std::forward<T>(t))...);
(std::cout << ... << std::get<sizeof...(Is1)+Is2>(std::forward<T>(t)))
<< '\n';
}
下面是一个完整的编译C++17的例子
#include <iostream>
#include <utility>
#include <tuple>
template <typename T>
struct num_args
: public num_args<decltype(&T::operator())>
{ };
template <typename R, typename ... Args>
struct num_args<R(*)(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename ... Args>
struct num_args<R(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename C, typename ... Args>
struct num_args<R(C::*)(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename C, typename ... Args>
struct num_args<R(C::*)(Args...) const>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <std::size_t ... Is1, std::size_t ... Is2, typename F, typename T>
void combine_helper (std::index_sequence<Is1...>,
std::index_sequence<Is2...>,
F & func, T && t)
{
func(std::get<Is1>(std::forward<T>(t))...);
(std::cout << ... << std::get<sizeof...(Is1)+Is2>(std::forward<T>(t)))
<< '\n';
}
template <typename F, typename ... Args>
void combine (F & func, Args && ... as)
{
constexpr auto n1 { num_args<F>::value };
constexpr auto n2 { sizeof...(Args) - n1 };
combine_helper(std::make_index_sequence<n1>{},
std::make_index_sequence<n2>{},
func,
std::forward_as_tuple(std::forward<Args>(as)...));
}
void func_1 (int a, int b, int c)
{ std::cout << "the product is: " << a*b*c << '\n'; }
int main()
{
auto extra { 100 };
auto func_2 { [&](int a, int b, int c, int d)
{ std::cout << "the extra sum is: " << extra+a+b+c+d << '\n'; } };
combine(func_1, 1, 2, 3, 4, 5, 6);
combine(func_2, 1, 2, 3, 4, 5, 6);
}
假设我有接受 1 个可调用 F 和可变参数列表的函数:
template <class F, class ...Args>
void combine(F& f, Args&& ... args)
F
可以有从 1 到 sizeof...(Args)
的任意数量的参数。所以我需要使用 c++17 来调用 F
,然后将未使用的参数放入 std::cout
,就像那样
{
std::invoke(f, [some way to restrict args]);
std::cout << [The rest of args] << "\n";
}
最大的问题是检测 F
的参数数量。
正如 Igor Tandetnik 在评论中指出的那样,这通常是不可能的,因为 f
函数可以是可变的,可以是具有模板 operator()
的 lambda 或实例一个 class/struct 和多个 operator()
.
无论如何...在某些情况下,您可以使用以下内容检测参数的数量
template <typename T>
struct num_args
: public num_args<decltype(&T::operator())>
{ };
template <typename R, typename ... Args>
struct num_args<R(*)(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
// other specialization follows
此时,您可以编写 combine()
来调用具有适当索引和参数元组的辅助函数
template <typename F, typename ... Args>
void combine (F & func, Args && ... as)
{
constexpr auto n1 { num_args<F>::value };
constexpr auto n2 { sizeof...(Args) - n1 };
combine_helper(std::make_index_sequence<n1>{},
std::make_index_sequence<n2>{},
func,
std::forward_as_tuple(std::forward<Args>(as)...));
}
辅助函数可以简单如下
template <std::size_t ... Is1, std::size_t ... Is2, typename F, typename T>
void combine_helper (std::index_sequence<Is1...>,
std::index_sequence<Is2...>,
F & func, T && t)
{
func(std::get<Is1>(std::forward<T>(t))...);
(std::cout << ... << std::get<sizeof...(Is1)+Is2>(std::forward<T>(t)))
<< '\n';
}
下面是一个完整的编译C++17的例子
#include <iostream>
#include <utility>
#include <tuple>
template <typename T>
struct num_args
: public num_args<decltype(&T::operator())>
{ };
template <typename R, typename ... Args>
struct num_args<R(*)(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename ... Args>
struct num_args<R(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename C, typename ... Args>
struct num_args<R(C::*)(Args...)>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename C, typename ... Args>
struct num_args<R(C::*)(Args...) const>
: public std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <std::size_t ... Is1, std::size_t ... Is2, typename F, typename T>
void combine_helper (std::index_sequence<Is1...>,
std::index_sequence<Is2...>,
F & func, T && t)
{
func(std::get<Is1>(std::forward<T>(t))...);
(std::cout << ... << std::get<sizeof...(Is1)+Is2>(std::forward<T>(t)))
<< '\n';
}
template <typename F, typename ... Args>
void combine (F & func, Args && ... as)
{
constexpr auto n1 { num_args<F>::value };
constexpr auto n2 { sizeof...(Args) - n1 };
combine_helper(std::make_index_sequence<n1>{},
std::make_index_sequence<n2>{},
func,
std::forward_as_tuple(std::forward<Args>(as)...));
}
void func_1 (int a, int b, int c)
{ std::cout << "the product is: " << a*b*c << '\n'; }
int main()
{
auto extra { 100 };
auto func_2 { [&](int a, int b, int c, int d)
{ std::cout << "the extra sum is: " << extra+a+b+c+d << '\n'; } };
combine(func_1, 1, 2, 3, 4, 5, 6);
combine(func_2, 1, 2, 3, 4, 5, 6);
}