假设我有一个像这样的结构:
struct Foo {
int a;
float b;
bool c;
};
还有像这样的模板化函数:
template<typename ...Ts> void func();
我如何编写一个使用 Foo 的字段类型调用
func()
的函数,如下所示:expand<Foo>(); // will call func<int,float,bool>();
实现
Rikus Honey
想法,
适用于 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
这个答案的灵感来自于这里的片段。
可以使用 C++17 中的结构化绑定来完成一些技巧来实现简单的静态反射。当检测到 C++17 时,Boost::PFR(或上面提到的magic get)基本上使用相同的技术,但如果您不想导入该库,我将提供一个简化的实现:
#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 个成员,但您可以扩展实现以支持您想要的成员数量。如果您发现编写这些样板文件很乏味,您可以尝试我编写的this header-only utility。它使用宏生成支持任意数量成员的代码,但需要 boost 来构建。