创建一个C++ std::tuple投影函数

3
我正在寻找一个适用于std::tuple的投影函数。也就是说,该函数接收一组整数作为模板参数,并返回仅包含这些索引处值的元组。
例如,假设我有一个元组tuple<int,String,char,float> t,那么调用project<1,3>(t)将会得到一个类型为tuple<String,float>的元组。
当然,关键似乎在于递归模板。但是,我无法使其正常工作。我尝试首先声明一个结构体来计算投影操作的返回类型。即使如此,它也失败了。以下是我的尝试:
template<typename T, size_t... indexes>
class Projection{
};

// Specialization for no index => Empty tuple
template<>
template<typename... T>
class Projection<std::tuple<T...>>{
   typedef std::tuple<T...> InputTuple;
   typedef std::tuple<> Tuple;
};

// Specialization for one or more parameters
template<size_t Index1, size_t... others>
template<typename... T>
class Projection<std::tuple<T...>,Index1,others...>{
    typedef std::tuple<T...> InputTuple;

    // The type of a projection with one column less
    typedef Projection<std::tuple<T...>,others...> TupleMinusOne;

    // The result type is the catenation of TupleMinusOne plus the column projected in this     step
    typedef decltype(std::tuple_cat(std::make_tuple(std::get<Index1>(InputTuple())),typename TupleMinusOne::Tuple())) Tuple;
};

这个可以编译通过。对于空元组的基本情况也适用,例如:

Projection<std::tuple<int,std::string>>::Tuple t;

t为空元组是递归基,但递归情况无法编译:

Projection<std::tuple<int,std::string>,1>::Tuple t;

我收到以下错误信息:

Test.cpp:79:1: error: ‘Tuple’ is not a member of ‘Projection<std::tuple<int, float>, 1ul>’

看起来递归情况没有被识别,但为什么呢?

2个回答

3

递归模板很少是必要的;参数包扩展通常更清晰简单。在这种情况下,只需使用tuple_element

template<typename T, size_t... indexes>
class Projection{
public:
    using Tuple = std::tuple<typename std::tuple_element<indexes, T>::type...>;
};

同样适用于 project
template<size_t... indexes, typename T>
auto project(const T &t) -> typename Projection<T, indexes...>::Tuple {
    return typename Projection<T, indexes...>::Tuple(std::get<indexes>(t)...);
}

我之前不知道有pack expansion这个东西,看起来简单多了,谢谢。但是你的类无法编译。当我添加它并尝试使用Projection<std::tuple<int,std::string>,1>::Tuple t;进行实例化时,我收到了大约10个错误。 - gexicide
@gexicide 抱歉,参数顺序搞错了。已修复。 - ecatmur
这个类现在可以工作了,谢谢!但是当像这样调用函数时,它仍然无法编译: std::tuple<int,int,float,std::string> t {1,1,4.5,"bla"}; std::tuple<int,float> f= project<1,2,std::tuple<int,int,float,std::string>>(t); - gexicide
@gexicide 在 project 函数的最后一个参数中省略掉:project<1,2>(t) - 在可变参数列表之后无法提供参数,必须推断。 - ecatmur
以前不知道这个,现在它非常出色,非常感谢您的快速和详细的帮助! - gexicide

1
您可以使用以下内容:
#define Return(ret) decltype(ret) { return ret; }

template<std::size_t... Is, typename T>
auto project(const T& t) -> Return(std::make_tuple(std::get<Is>(t)...))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接