如何使用递归类模板在 C++11 中写出元组的内容

How to write out contents of a tuple in C++11 using recursive class templates?

本文关键字:元组 C++11 递归 何使用      更新时间:2023-10-16

我尝试了以下递归来写出tuple的元素,但是在编译时计算tuple大小的行中遇到了麻烦(下面注释掉了):

#include <tuple>
#include <string>
#include <iostream>
template<typename Tuple, std::size_t element = 0>
struct write_tuple
{
    static void execute(Tuple const & t)
    {
        std::cout << std::get<element>(t) << std::endl; 
        write_tuple<Tuple, element + 1>::execute(t); 
    }
};
template<typename Tuple>
struct write_tuple<Tuple, 4>  // This works fine
//struct write_tuple<Tuple, std::tuple_size<typename Tuple>::value >  // std::tuple_size should give me the size of the tuple at compile-time
{
    static void execute(Tuple const & t) {}; 
};
template<typename Tuple>
void write(Tuple const & t)
{
    write_tuple<Tuple>::execute(t); 
}
using namespace std;
int main(int argc, const char *argv[])
{
    tuple<string, int, double, string> myTuple = std::make_tuple("test", 0, 2.1, "finished"); 
    write(myTuple);
    return 0;
}

该行:

struct write_tuple<Tuple, 4> 

可以很好地终止大小为 4 的tuple的递归调用,但是当我在编译时使用std::tuple_size<typename Tuple>::value获取tuple大小时,出现以下错误:

main.cpp:17:57: error: template argument 1 is invalid
     struct write_tuple<Tuple, std::tuple_size<typename Tuple>::value >  // std::tuple_size should give me the size of the tuple at compile-time
                                                             ^
main.cpp:17:66: error: template argument 2 is invalid
     struct write_tuple<Tuple, std::tuple_size<typename Tuple>::value >  // std::tuple_size should give me the size of the tuple at compile-time

我正在使用 gcc 4.8.2。

编辑:

std::tuple_size<typename Tuple>::value结果中删除typename,并显示以下错误:

g++ -std=c++11 main.cpp -o main  2>&1 | tee log 
main.cpp:17:8: error: template argument ‘std::tuple_size<_Tp>::value’ involves template parameter(s)
 struct write_tuple<Tuple, std::tuple_size<Tuple>::value>  // std::tuple_size should give me the size of the tuple at compile-time

对于您的代码,您可以反转递归,例如:

template<typename Tuple, std::size_t remaining>
struct write_tuple
{
    static void execute(Tuple const & t)
    {
        std::cout << std::get<std::tuple_size<Tuple>::value - remaining>(t) << std::endl;
        write_tuple<Tuple, remaining - 1>::execute(t);
    }
};
template<typename Tuple>
struct write_tuple<Tuple, 0>
{
    static void execute(Tuple const & t) {};
};
template<typename Tuple>
void write(Tuple const & t)
{
    write_tuple<Tuple, std::tuple_size<Tuple>::value>::execute(t);
}

另一种方法:

#include <tuple>
#include <iostream>
#include <cstdint>
#if 1 // Not in C++11
template <std::size_t ...> struct index_sequence {};
template <std::size_t N, std::size_t ...Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};
template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
#endif // make_index_sequence
template<typename Tuple>
struct write_tuple
{
    static void execute(Tuple const & t)
    {
        execute(t, make_index_sequence<std::tuple_size<Tuple>::value>());
    }
private:
    template<std::size_t ... Is>
    static void execute(Tuple const & t, index_sequence<Is...>)
    {
        const int dummy[] = {0, (write_element(std::get<Is>(t)), 0)...};
        static_cast<void>(dummy); // silent warning for unused variable.
    }
    template <typename T>
    static void write_element(T const &elem)
    {
        std::cout << elem << std::endl;
    }
};

这是该语言的一个怪癖:非类型参数值不能依赖于专用化中的类型参数值。 标准化委员会可能是有原因的。 这可能是一个好主意。

有几种方法可以解决您的问题,最简单的 beimg 递归到0并在返回递归的途中打印。 对代码进行最少更改的一种方法是将, typename=void>参数添加到class template,并在专用化中添加大小,然后, size, typename std::enable_if<size==std::tuple_size<Tuple>::value>::type>添加到专用化末尾。 这使得测试成为类型参数,专门用于void(始终存在),但仅在 SFINAE 成功且大小与元组大小匹配时才有效。