如何开发 boost::pfr::for_each 的 constexpr 实现?
How to develop a constexpr implementation of boost::pfr::for_each?
我正在使用 boost::pfr
,它使用反射的方式令人印象深刻,无需任何变量的宏注册。
但我想知道的问题是为什么 boost::pfr::for_each
没有声明为 constexpr,避免在当前情况下在用户声明的任何 constexpr 函数中使用 PFR for_each
。
有什么方法可以在不更改原始 boost::pfr 源代码的情况下绕过这个问题?
编辑:我在 coliru 中包含了一个工作示例和 link 来说明我的观点。
https://coliru.stacked-crooked.com/a/443f8bd2ad66ca4c
#include <iostream>
#include "boost/pfr.hpp"
struct Variable
{
};
struct Var1 : public Variable
{
static constexpr int size { 5 };
};
struct Var2 : public Variable
{
static constexpr int size { 10 };
};
struct Var3//This one does not depend of class Variable!
{
static constexpr int size { 20 };
};
struct Packet
{
Var1 var1;
Var2 var2;
Var3 var3;
};
template<typename T>
constexpr int accumulate(const T& ref) {
int result{};
boost::pfr::for_each_field(ref, [&](auto& field) { if (std::is_base_of<Variable, std::decay_t<decltype(field)>>::value) result += field.size; });
return result;
}
int main()
{
Packet packet;
/*constexpr*/ auto size = accumulate(packet);//constexpr must be commented!
std::cout << size;
//static_assert(size == 15);//It can not be used due to non-constexpr!
}
这看起来像是对实现的疏忽,因为它很容易成为 constexpr,至少对于 C++17 实现而言 - godbolt example
与此同时,您可以使用 boost::pfr::structure_tie
(即 constexpr)& std::apply
:
构建自己的 constexpr
template<class T, class F>
constexpr void for_each_field(T&& obj, F&& func) {
std::apply([f = std::forward<F>(func)](auto&&... elements) mutable {
(std::forward<F>(f)(std::forward<decltype(elements)>(elements)), ...);
}, boost::pfr::structure_tie(std::forward<T>(obj)));
}
我正在使用 boost::pfr
,它使用反射的方式令人印象深刻,无需任何变量的宏注册。
但我想知道的问题是为什么 boost::pfr::for_each
没有声明为 constexpr,避免在当前情况下在用户声明的任何 constexpr 函数中使用 PFR for_each
。
有什么方法可以在不更改原始 boost::pfr 源代码的情况下绕过这个问题?
编辑:我在 coliru 中包含了一个工作示例和 link 来说明我的观点。
https://coliru.stacked-crooked.com/a/443f8bd2ad66ca4c
#include <iostream>
#include "boost/pfr.hpp"
struct Variable
{
};
struct Var1 : public Variable
{
static constexpr int size { 5 };
};
struct Var2 : public Variable
{
static constexpr int size { 10 };
};
struct Var3//This one does not depend of class Variable!
{
static constexpr int size { 20 };
};
struct Packet
{
Var1 var1;
Var2 var2;
Var3 var3;
};
template<typename T>
constexpr int accumulate(const T& ref) {
int result{};
boost::pfr::for_each_field(ref, [&](auto& field) { if (std::is_base_of<Variable, std::decay_t<decltype(field)>>::value) result += field.size; });
return result;
}
int main()
{
Packet packet;
/*constexpr*/ auto size = accumulate(packet);//constexpr must be commented!
std::cout << size;
//static_assert(size == 15);//It can not be used due to non-constexpr!
}
这看起来像是对实现的疏忽,因为它很容易成为 constexpr,至少对于 C++17 实现而言 - godbolt example
与此同时,您可以使用 boost::pfr::structure_tie
(即 constexpr)& std::apply
:
template<class T, class F>
constexpr void for_each_field(T&& obj, F&& func) {
std::apply([f = std::forward<F>(func)](auto&&... elements) mutable {
(std::forward<F>(f)(std::forward<decltype(elements)>(elements)), ...);
}, boost::pfr::structure_tie(std::forward<T>(obj)));
}