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