C++11: 如何编写一个像 Get 一样工作的模板函数<tuple>...但是收到参数包?

C++11: how to write a template function that works like get<tuple>... but receives param pack?

本文关键字:tuple lt gt 函数 参数 一个 何编写 Get C++11 工作 一样      更新时间:2023-10-16

我知道在 c++11 中,get<> 模板函数与 std::tuple 一起使用以获取元组的索引值,这在编译时解决。

但我的要求是有一个名为get的模板函数<>但接收一个参数包,所以代码应该如下所示:

#include<iostream>
using namespace std;
template<typename Head, typename ... Tail>
auto get(size_t index, Head&& t, Tail&&...tail){
return get(index-1, tail...);
}
template<typename Head, typename ... Tail>
Head get<0>(Head&& t, Tail&&...tail){
return t;
}
int main(){
cout<<get(3,"abc",'x',27,"hello")<<endl;
cout<<get(2,"abc",'x',28,"hello")<<endl;
return 0;
}

好吧,它肯定不会编译,因为我不知道如何编写这样的"get"模板函数。我希望主函数将运行并打印如下:

hello
28

所以我的问题:如何实现我上面提到的这个"获取"模板? 谢谢!

真的需要能够在运行时选择索引吗?如果没有,以下内容就足够了:

template <std::size_t Index, typename ...P> auto get(P &&... params)
{
return std::get<Index>(std::make_tuple(params...));
}
// ...
std::cout << get<1>("abc", 42, 123.456); // Prints 42

如果您确实希望将索引作为普通(运行时(参数,则必须返回std::variant<P...>(或std::any或标记的联合(,因为返回类型不能依赖于运行时参数。

可能的实现可能如下所示:

template <typename ...P> std::variant<P...> get(std::size_t index, P &&... params)
{
std::size_t pos = 0;
std::variant<P...> ret;
((index == pos++ ? void(ret = params) : void()) , ...);
return ret;
}
// ...
std::cout << std::get<int>( get(1, "abc", 42, 123.456) ); // Prints 42 too, but looks ugly

或者,您可以将返回类型指定为模板参数:

template <typename T, typename ...P> T get(std::size_t index, P &&... params)
{
std::size_t pos = 0;
std::variant<P...> va;
((index == pos++ ? void(va = params) : void()) , ...);
if (T *ptr = std::get_if<T>(va))
return T;
else
throw /*something*/;
}
// ...
std::cout << get<int>(1, "abc", 42, 123.456); // 42

或者您可以将值传递给函数/函子:(谢谢@Yakk(

template <typename T, typename ...P> void get(std::size_t index, T &&func, P &&... params)
{
std::size_t pos = 0;
((index == pos++ ? void(func(params)) : void()) , ...);
}
// ...
get(1, [](int x){std::cout << x;}, "abc", 42, 123.456); // 42
// Alternative:
// get(1, [](auto x){std::cout << x;}, "abc", 42, 123.456); // 42 too, 
// but you could print any type which can be printed without having to 
// specify the type manually.