在C++中,当需要将一个元组的所有元素作为函数的实参时,可以使用可变参数模板和递归来实现一个解包函数。但是这不仅增加了代码的复杂度,也增加了编译时间。基于此,C++17引入std::apply,可以方便的将元组作为参数传递给函数。
std::apply的函数签名如下:
template <class_Callable, class_Tuple>
constexpr decltype(auto) apply(_Callable&& _Obj,
_Tuple&& _Tpl) noexcept
其中_obj为可调用体,_Tpl为元组。由此可知apply存在可调用体和元组两部分。
apply的可调用体
在C++中可调用体的类型较多,可以是函数、模板,还可以是lambda表达式等
1. 函数
int add(int a, int b)
{
return a+b;
}
void using_apply_with_function()
{
std::tuple<int,int> tuple = {3,4};
int ret = std::apply(add, tuple);
std::cout<<"add with function is result is "<<ret<<"\n";
}
2. 模板
template<typenameT>
concept con_add = requires(T a, T b)
{
{a+b}->std::same_as<T>;
};
//结合c++20 concept
template<con_addT>
Ttemplate_add(T a, T b)
{
return a+b;
}
void using_apply_with_template()
{
auto ret = std::apply(template_add<int>, std::make_tuple(30,40));
std::cout << "add with template is result is " << ret << "\n";
}
3. lambda
void using_apply_with_lambda()
{
auto f = [](int a, int b,int c)->int{
returna+b+c;
};
std::tuple<int,int,int>par{3,5,6};
autoret=std::apply(f,par);
std::cout<<"addwithlambdaisresultis"<<ret<<"\n";
}
4. std::functional
void using_apply_with_functional()
{
std::function<int(int,int,int)> f = [](int a, int b, int c)->int {
return a + b + c;
};
std::tuple<int, int, int > par{ 3,5,6 };
auto ret = std::apply(f, par);
std::cout << "add with functional is result is " << ret << "\n";
}
5. 函数对象
class DD {
public:
void operator()(int a, int b)
{
std::cout<<a<<"+"<<b<<"="<<a+b<<"\n";
}
};
void using_apply_with_obj()
{
DD dd;
std::tuple<int, int> par{9,10};
std::apply(dd,par);
}
6. 可变参数模板
// 使用参数包计算参数的总和
template<typename... Args>
auto sum(Args... args) {
return (args + ...);
}
void using_apply_with_variable_par() {
auto p = std::make_tuple<int, int, int>(1, 20, 50);
auto ret = std::apply([](auto... args) { returnsum(args...); }, p);
std::cout << "add with variable par is result is " << ret << "\n";
auto p1 = std::make_tuple<int, int, int>(1, 20, 50,80);
ret = std::apply([](auto... args) { returnsum(args...); }, p1);
std::cout << "add with variable par is result is " << ret << "\n";
}
apply的元组
apply的元组并不仅仅局限于std::tuple,不仅可以是tuple,还可以是array,还可以是pair
void using_apply_different_tuple()
{
//tuple
std::tuple<int, int> tuple = { 3,4 };
int ret = std::apply(add, tuple);
std::cout << "add with tuple is result is " << ret << "\n";
//array
std::array<int, 2> arr{ 1,6 };
ret = std::apply(add, arr);
std::cout << "add with array is result is " << ret << "\n";
//pair
ret = std::apply(add, std::pair(1, 6));
std::cout << "add with pair is result is " << ret << "\n";
}
注意
在使用apply时,请注意元组中元素的数量必须和可调用体的形参数量一致,或参数个数可以是任意个,否则将出现编译错误。