C++11:如何编写一个类似于 get<tuple>... 但接收参数包的模板函数?

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

我知道在 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

所以我的问题是:如何实现我上面提到的 "get" 模板? 谢谢!

真的需要能够在运行时select索引吗?如果没有,以下应该足够了:

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

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

一个可能的实现可能是这样的:

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

或者您可以指定 return 类型作为模板参数:

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

或者您可以将值传递给 function/functor:(感谢@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.