如何使用递归类模板在C++11中写出元组的内容?
我尝试了以下递归来写出元组的元素,但在编译时计算元组大小的行中遇到了问题,如下所述:如何使用递归类模板在C++11中写出元组的内容?,c++,templates,c++11,stl,tuples,C++,Templates,C++11,Stl,Tuples,我尝试了以下递归来写出元组的元素,但在编译时计算元组大小的行中遇到了问题,如下所述: #include <tuple> #include <string> #include <iostream> template<typename Tuple, std::size_t element = 0> struct write_tuple { static void execute(Tuple const & t) {
#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;
}
我使用的是GCC4.8.2
编辑:
从std::tuple\u size::value中删除typename会导致以下错误:
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
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
这是语言的一个怪癖:非类型参数值不能依赖于专门化中的类型参数值。标准化委员会可能有原因。这可能是个好消息
有几种方法可以解决您的问题,最简单的方法是递归到0并在返回递归的过程中打印。对代码进行最少更改的一个方法是向类模板添加一个,typename=void>参数,并在专门化中添加size in,然后在专门化的末尾添加size,typename std::enable_if::type>。这使得测试在一个类型参数中进行,该参数在void上进行了专门化,void始终存在,但只有在SFINAE成功且大小与元组大小匹配时才有效。这是语言的一个怪癖:非类型参数值不能依赖于专门化中的类型参数值。标准化委员会可能有原因。这可能是个好消息
有几种方法可以解决您的问题,最简单的方法是递归到0并在返回递归的过程中打印。对代码进行最少更改的一个方法是向类模板添加一个,typename=void>参数,并在专门化中添加size in,然后在专门化的末尾添加size,typename std::enable_if::type>。这使得测试在一个类型参数中进行,该参数在void上专用,它始终存在,但只有在SFINAE成功且大小与元组大小匹配时才有效。对于您的代码,您可以反转递归,如:
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;
}
};
对于您的代码,您可以反转递归,如:
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;
}
};
将std::tuple\u size::value更改为std::tuple\u size::value。typename关键字在该上下文中无效。@user1353535:谢谢,我已经试过了,请参见编辑的问题。它无法推断专门化。看,更好的方法是从tuple_size倒计时到0,而不是从0到tuple_size倒计时@user1353535:谢谢你提出的另一个问题,我正在阅读。将std::tuple\u size::value更改为std::tuple\u size::value。typename关键字在该上下文中无效。@user1353535:谢谢,我已经试过了,请参见编辑的问题。它无法推断专门化。看,更好的方法是从tuple_size倒计时到0,而不是从0到tuple_size倒计时@用户1353535:谢谢你的另一个问题,我正在读。