我试图递归地遍历类型列表,以便我可以根据列表中的每种类型执行一些运行时代码。我希望能够在不使用“ if constexpr”来终止递归的情况下,以递归方式遍历结构体中函数的元组中的所有类型(而不是结构体中的函数)。
我有一小段代码,展示了使用constexpr进行递归操作。
@Document(collection = "user")
public class User extends AbstractEntity{
private String name;
private String lastName;
private ????? address
...
}
我希望能够使用C ++ 14(而不是带有“ if constexpr”的C ++ 17)进行相同的递归。
谢谢!
答案 0 :(得分:7)
诀窍是使用index_sequence
。
这是 C ++ 14 的工作解决方案,使用@MartinMorterol建议进行了改进。
// -*- compile-command: "g++ -Wall -std=c++14 poub.cpp; ./a.out"; -*-
#include <iostream>
#include <string>
#include <tuple>
#include <type_traits>
template <typename... Ts>
struct temp
{
using TypeList = std::tuple<Ts...>;
constexpr static std::size_t _N = std::tuple_size<TypeList>::value;
void print_this() { _inner_print(std::make_index_sequence<_N>()); }
template <std::size_t... IDX>
void _inner_print(std::index_sequence<IDX...>)
{
auto dummy = {0, (_inner_print<IDX>(),0)...};
(void)dummy;
}
template <std::size_t IDX>
void _inner_print()
{
std::cout << "\nCall #" << IDX
<< " sizeof " << sizeof(std::get<IDX>(_mem));
}
TypeList _mem;
};
int main()
{
std::string name;
temp<int, double, char> t1;
t1.print_this();
}
打印:
g++ -Wall -std=c++14 poub.cpp; ./a.out
Call #0 sizeof 4
Call #1 sizeof 8
Call #2 sizeof 1
我的最初答案(使用递归)
// -*- compile-command: "g++ -std=c++14 poub.cpp; ./a.out"; -*-
#include <iostream>
#include <string>
#include <tuple>
#include <type_traits>
template <typename... Ts>
struct temp
{
using TypeList = std::tuple<Ts...>;
constexpr static std::size_t _N = std::tuple_size<TypeList>::value;
void print_this() { _inner_print(std::make_index_sequence<_N>()); }
template <std::size_t... IDX>
void _inner_print(std::index_sequence<IDX...>)
{
_inner_print(std::integral_constant<std::size_t, IDX>()...);
}
template <std::size_t HEAD_IDX, typename... TAIL>
void _inner_print(std::integral_constant<std::size_t, HEAD_IDX>, TAIL... tail)
{
std::cout << "\nCall #" << HEAD_IDX
<< " sizeof " << sizeof(std::get<HEAD_IDX>(_mem));
// whatever you want HERE ...
_inner_print(tail...);
}
void _inner_print(){};
TypeList _mem;
};
int main()
{
std::string name;
temp<int, double, char> t1;
t1.print_this();
}
答案 1 :(得分:5)
如果您可以将_inner_print
函数更改为一个类,则可以使用部分特殊化来结束递归:
template <std::size_t N, std::size_t MAX>
struct _inner_print
{
_inner_print()
{
std::cout << "Call #"<<MAX-N<<std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
_inner_print<N-1, MAX>();
}
};
template <std::size_t MAX> struct _inner_print<0, MAX> { };
它不是作为函数调用_inner_print()
,而是变为未命名临时变量的声明,并调用执行输出的构造函数。
答案 2 :(得分:4)
您应该使用部分专业化。但是您不能使用函数来做到这一点。
您应该使用struct
来完成技巧。
#include <iostream>
#include <string>
#include <tuple>
template <std::size_t N, std::size_t MAX, class T>
struct inner_print_impl{
static void run(const T& caller)
{
std::cout << "Call #"<<MAX-N<< " " << caller.a << std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
inner_print_impl<N-1, MAX , T>::run(caller);
}
};
template < std::size_t MAX, class T>
struct inner_print_impl<0, MAX , T>{
static void run(const T& caller)
{
std::cout << "Call #"<<MAX<< " " << caller.a << std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
// no recursion
}
};
template <typename ...Ts>
struct temp{
using TypeList = std::tuple<Ts...>;
constexpr static std::size_t N_ = std::tuple_size<TypeList>::value;
template <std::size_t N, std::size_t MAX, class T>
friend struct inner_print_impl;
void print_this()
{
inner_print_impl<N_,N_, temp<Ts...> >::run(*this);
}
TypeList _mem;
private :
int a ; // test acces
};
int main()
{
std::string name;
temp<int, int, int> t1;
t1.print_this();
}
注意:
*this
传递给通话,并将新的struct
添加为班级的朋友/* other dynamic code */
部分上有一个重复项。你可以 :
int
而不是size_t
,然后停在-1
而不是0
PS:
我没有得到部分
结构体中函数的元组中(而不是结构体中的函数)
我希望我不会错过任何事情
编辑:
我的代码比您的代码执行了更多的迭代,您可以将其清空:
template < std::size_t MAX, class T>
struct inner_print_impl<0, MAX , T>{
static void run(const T& caller)
{
}
};
您不会在0
情况下显示。
答案 3 :(得分:0)
template<class Integral, Integral N>
auto dispatch( std::integral_constant<Integral, N> ) {
return [](auto&&...args){
return std::get<N>( std::forward_as_tuple( decltype(args)(args)... ) );
};
}
template<std::size_t N>
auto dispatch() {
return dispatch( std::integral_constant<std::size_t, N>{} );
}
这种小小的美丽给了您c++14中if constexpr
的魔力。
template <std::size_t N, std::size_t MAX>
void _inner_print() {
dispatch( std::integral_constant<bool, N==0>{} )
(
// 0, aka false branch:
[&](auto Nval){
std::cout << "Call #"<<MAX-Nval<<std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
_inner_print<Nval-1, MAX>();
},
// 1, aka true branch:
[](auto&&){}
)( std::integral_constant<std::size_t, N>{} );
}
请注意,我们必须通过lambda的参数传递N
,因为我们希望lambda的主体的有效性根据其参数而变化,该参数仅传递给正确的参数。
或者,您可以使用overload
助手:
template<class T0, class...Ts>
struct overloaded;
template<class Lhs, class Rhs, class...Ts>
struct overloaded<Lhs, Rhs, Ts...>:
overloaded<Lhs>, overloaded<Rhs,Ts...>
{
using overloaded<Lhs>::operator();
using overloaded<Rhs,Ts...>::operator();
template<class A0, class...As>
explicit overloaded(A0&&a0, As&&...as) :
overloaded<Lhs>(std::forward<A0>(a0)),
overloaded<Rhs,Ts...>( std::forward<As>(as)... )
{}
overloaded(overloaded const&)=default;
overloaded(overloaded &&)=default;
overloaded& operator=(overloaded const&)=default;
overloaded& operator=(overloaded &&)=default;
};
template<class T0>
struct overloaded<T0> : T0 {
using T0::operator();
template<class A0>
explicit overloaded(A0&&a0):
T0(std::forward<A0>(a0))
{}
overloaded(overloaded const&)=default;
overloaded(overloaded &&)=default;
overloaded& operator=(overloaded const&)=default;
overloaded& operator=(overloaded &&)=default;
};
template<class R, class...Args>
struct overloaded<R(*)(Args...)> {
R operator()(Args... args) const {
return pf(std::forward<Args>(args)...);
}
R(*pf)(Args...);
overloaded( R(*f)(Args...) ):pf(f) {}
overloaded(overloaded const&)=default;
overloaded(overloaded &&)=default;
overloaded& operator=(overloaded const&)=default;
overloaded& operator=(overloaded &&)=default;
};
template<class...Args>
auto overload( Args&&...args ) {
return overloaded<std::decay_t<Args>...>(
std::forward<Args>(args)...
);
}
您可以在这里使用overloaded
:
template <std::size_t N, std::size_t MAX>
void _inner_print()
{
std::integral_constant<std::size_t, N> index;
overload(
[](std::integral_constant<std::size_t, 0>) {},
[&](auto index) {
std::cout << "Call #"<<MAX-index<<std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
_inner_print<index-1, MAX>();
}
)(index);
}
请注意,规则是,有时仅编译动态代码必须取决于lambda的auto
参数。