将结构字段的类型展开为可变模板参数

Expand types of struct fields into variadic template arguments

本文关键字:参数 字段 结构 类型      更新时间:2023-10-16

假设我有一个这样的结构:

struct Foo {
int a;
float b;
bool c;
};

像这样的模板化函数:

template<typename ...Ts> void func();

如何编写一个使用Foo的字段类型调用func()的函数,比如:expand<Foo>(); // will call func<int,float,bool>();

这个答案的灵感来自这里的片段。

一些技巧可以在C++17中使用结构化绑定来实现简单的静态反射。Boost::PFR(或上面提到的魔术(在检测到C++17时基本上使用相同的技术,但如果您不想导入该库,我将提供一个简化的实现:

#include <type_traits>
template <class T, class... TArgs>
decltype(void(T{std::declval<TArgs>()...}), std::true_type{}) test_is_braces_constructible(int);
template <class, class...>
std::false_type test_is_braces_constructible(...);
template <class T, class... TArgs>
using is_braces_constructible = decltype(test_is_braces_constructible<T, TArgs...>(0));
struct any_type {
template<class T>
constexpr operator T(); // non explicit
};
template<typename T, template <typename ...Unused> typename R>
constexpr auto extractTypes() noexcept {
using Type = std::decay_t<T>;
Type* tptr;
if constexpr(is_braces_constructible<Type, any_type, any_type>{}) {
auto& [ m0, m1 ] = *tptr;
return R< std::decay_t<decltype(m0)>, std::decay_t<decltype(m1)> > {};
} else if constexpr(is_braces_constructible<Type, any_type>{}) {
auto&& [m0] = *tptr;
return R< std::decay_t<decltype(m0)> > {};
} else {
return R<> {};
}
}

上述代码中的extractTypes()接受聚合可初始化类型T来反映,并接受可变模板R来接收提取的类型。您可以将要对这些类型执行的操作放入结构R:中

template <typename ...Types>
struct R {
static void doStuffs() {
(operation<Types>(), ...);
}
};

在上面的代码中,T最多可以容纳2个成员,但您可以扩展实现以支持所需的成员数量。如果你觉得写那些样板文件很乏味,你可以试试我写的这个只有标题的实用程序。它使用宏生成支持任意数量成员的代码,但需要boost才能构建。

实现CCD_ 8思想,适用于c++17或以上

如果您可以使用所需的类型为结构提供元组成员;

你可以像下面这样做;

struct Foo 
{
std::tuple<int, float, bool> tpl_;
};
template <class...Ts>
void test( Ts... ) {}
int main()
{
Foo f;

std::apply( []( auto&&...args ) { test( args... ); }, f.tpl_ );
}

好点@user975989