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

问题描述 投票:0回答:2

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

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

还有像这样的模板化函数:

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

我如何编写一个使用 Foo 的字段类型调用

func()
的函数,如下所示:
expand<Foo>(); // will call func<int,float,bool>();

c++ templates metaprogramming
2个回答
0
投票

实现

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


0
投票

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

可以使用 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 来构建。

© www.soinside.com 2019 - 2024. All rights reserved.