How to develop a constexpr implementation of boost::pfr::for_each?

Viewed 171

I am using boost::pfr and it's quite impressive the way it uses reflection without any neccesity of macro registering of variables.

But the issue I wonder is why boost::pfr::for_each was not declared as constexpr, avoiding in current situation the use of PFR for_each within any constexpr function declared by users.

Is there any way I can bypass this issue without changing original boost::pfr source code?

EDIT: I include a working example and a link to coliru to show my point.

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!
}
1 Answers

This looks like an oversight in the implementation, given that it could easily be constexpr, at least for the C++17 implementation - godbolt example

In the meantime you can build your own constexpr one using boost::pfr::structure_tie (which is constexpr) & std::apply:

godbolt example

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)));
}
Related