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

时间:2021-09-10 05:46:07

I tried the following recursion to write out the elements of a tuple, but I have trouble in the line that computes the tuple size at compile time (commented out below):

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

#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;
}

The line:

struct write_tuple<Tuple, 4> 

works perfectly fine to terminate the recursive call for a tuple of size 4, but when I use the std::tuple_size<typename Tuple>::value to get the tuple size at compile time, I get the following error:

完全正常工作以终止大小为4的元组的递归调用,但是当我使用std :: tuple_size :: value在编译时获取元组大小时,我收到以下错误:

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

I am using gcc 4.8.2.

我正在使用gcc 4.8.2。

Edit:

removing the typename from std::tuple_size<typename Tuple>::value results with the following error:

从std :: tuple_size :: 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

2 个解决方案

#1


3  

For your code, you may reverse the recursion, like:

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

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);
}

An alternative approach:

另一种方法:

#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;
    }
};

#2


1  

It is a quirk of the language: non-type parameter values cannot be dependent on type parameter values in a specialization. Probably the standardization comittee had a reason. It may have been a good one.

这是语言的一个怪癖:非类型参数值不能依赖于特化中的类型参数值。可能是标准化委员会有理由。它可能是一个很好的。

There are a few ways to solve your problem, the easiest beimg to recurse down to 0 and print on the way back up the recursion. One that involves the least change to your code would be to add a , typename=void> parameter to your class template, and in the specialization add the size in, then , size, typename std::enable_if<size==std::tuple_size<Tuple>::value>::type> added to the end of the specialization. This makes the test in a type parameter, specialized on void (which is always there), but only valid when SFINAE succeeds and the size matches the tuple size.

有几种方法可以解决您的问题,最简单的方法是将其递归到0并在返回的方式上打印。一个涉及对代码进行最少更改的方法是在类模板中添加一个typename = void>参数,并在特化中添加大小,然后,size,typename std :: enable_if :: value> :: type>添加到特化的末尾。这使得测试在一个类型参数中,专门针对void(总是存在),但仅在SFINAE成功且大小与元组大小匹配时才有效。

#1


3  

For your code, you may reverse the recursion, like:

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

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);
}

An alternative approach:

另一种方法:

#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;
    }
};

#2


1  

It is a quirk of the language: non-type parameter values cannot be dependent on type parameter values in a specialization. Probably the standardization comittee had a reason. It may have been a good one.

这是语言的一个怪癖:非类型参数值不能依赖于特化中的类型参数值。可能是标准化委员会有理由。它可能是一个很好的。

There are a few ways to solve your problem, the easiest beimg to recurse down to 0 and print on the way back up the recursion. One that involves the least change to your code would be to add a , typename=void> parameter to your class template, and in the specialization add the size in, then , size, typename std::enable_if<size==std::tuple_size<Tuple>::value>::type> added to the end of the specialization. This makes the test in a type parameter, specialized on void (which is always there), but only valid when SFINAE succeeds and the size matches the tuple size.

有几种方法可以解决您的问题,最简单的方法是将其递归到0并在返回的方式上打印。一个涉及对代码进行最少更改的方法是在类模板中添加一个typename = void>参数,并在特化中添加大小,然后,size,typename std :: enable_if :: value> :: type>添加到特化的末尾。这使得测试在一个类型参数中,专门针对void(总是存在),但仅在SFINAE成功且大小与元组大小匹配时才有效。