Repository navigation
rfl::to_view() does not seem to actually support being run at compile-time #712
Description
Activity
Oh, it occurs to me that you probably also want the error message from the compiler. This is what I get from Clang on macOS:
====================[ Build | all | Debug ]===================================== /Applications/CLion.app/Contents/bin/cmake/mac/aarch64/bin/cmake --build /Users/username/dev/private/projectname/cmake-build-debug --target all -j 12 [1/2] Building CXX object CMakeFiles/projectname-test.dir/main.cpp.o FAILED: CMakeFiles/projectname-test.dir/main.cpp.o /usr/bin/c++ -I/Users/username/dev/private/projectname -I/Users/username/dev/private/projectname/reflect-cpp/include -I/Users/username/dev/private/projectname/reflect-cpp/include/rfl/thirdparty -g -std=gnu++2b -arch arm64 -fcolor-diagnostics -MD -MT CMakeFiles/projectname-test.dir/main.cpp.o -MF CMakeFiles/projectname-test.dir/main.cpp.o.d -o CMakeFiles/projectname-test.dir/main.cpp.o -c /Users/username/dev/private/projectname/main.cpp /Users/username/dev/private/projectname/main.cpp:133:9: error: static assertion expression is not an integral constant expression 133 | get_packed_size<Pod>() == | ^~~~~~~~~~~~~~~~~~~~~~~~~ 134 | sizeof(std::uint16_t) + sizeof(std::uint32_t) + sizeof(float) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/main.cpp:124:23: note: non-literal type 'const NamedTuple<std::remove_cvref_t<Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>>, std::remove_cvref_t<Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>>, std::remove_cvref_t<Field<internal::StringLiteral<4>{{"baz"}}, float *>>>' (aka 'const NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>') cannot be used in a constant expression 124 | const auto view = rfl::to_view(unused); | ^ /Users/username/dev/private/projectname/main.cpp:133:9: note: in call to 'get_packed_size<Pod>()' 133 | get_packed_size<Pod>() == | ^~~~~~~~~~~~~~~~~~~~~~ 1 error generated. ninja: build stopped: subcommand failed.
I've also seen the same issue occur with MSVC on Windows. I'm not able to provide an error log for that, but it was complaining about essentially the same issue (
rfl::to_view()cannot be used in a constant expression).I did a bit of further digging and hacking on reflect-cpp. The underlying issue seems to be that a lot of the library's own types (NamedTuple, Tuple, etc...) aren't
LiteralTypeswhich precludes their use in template arguments and certain constexpr-contexts, in particular:- all their non-static data members must be public
- all the methods of them that are intended to be used in constant expressions need to be declared
constexpr.
I've tried hacking on reflect-cpp to make these changes, and I've hit a road-block at this particular method in
Tuple.hpp. I present here the modified version withXXXcomments added by me, documenting what I've tried...template <int... _is> constexpr void move_from_types(Types&&... _types, std::integer_sequence<int, _is...>) { const auto move_one = [this]<int _i>(auto&& _t, std::integral_constant<int, _i>) { using Type = internal::nth_element_t<_i, Types...>; // XXX: Can't use placement-new in constexpr til C++26! // ::new (static_cast<void*>(data_.data() + pos<_i>())) Type(std::move(_t)); // XXX: can't use reinterpret_cast() in constexpr either... std::construct_at(std::addressof(std::bit_cast<Type>(data_.data() + pos<_i>())), Type(std::move(_t))); }; (move_one(std::move(_types), std::integral_constant<int, _is>{}), ...); }
Note the
std::construct_at()version, the last one I tried, fails with the following log messages:Details
====================[ Build | all | Debug ]===================================== /Applications/CLion.app/Contents/bin/cmake/mac/aarch64/bin/cmake --build /Users/username/dev/private/projectname/cmake-build-debug --target all -j 12 [1/7] Building CXX object CMakeFiles/projectname-test.dir/main.cpp.o FAILED: CMakeFiles/projectname-test.dir/main.cpp.o /usr/bin/c++ -I/Users/username/dev/private/projectname -I/Users/username/dev/private/projectname/reflect-cpp/include -I/Users/username/dev/private/projectname/reflect-cpp/include/rfl/thirdparty -g -std=gnu++2b -arch arm64 -fcolor-diagnostics -MD -MT CMakeFiles/projectname-test.dir/main.cpp.o -MF CMakeFiles/projectname-test.dir/main.cpp.o.d -o CMakeFiles/projectname-test.dir/main.cpp.o -c /Users/username/dev/private/projectname/main.cpp In file included from /Users/username/dev/private/projectname/main.cpp:112: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl.hpp:10: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/AddStructName.hpp:6: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Field.hpp:8: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Literal.hpp:14: /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:174:25: error: call to deleted function 'addressof' 174 | std::construct_at(std::addressof(std::bit_cast<Type>(data_.data() + pos<_i>())), Type(std::move(_t))); | ^~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:176:6: note: in instantiation of function template specialization 'rfl::Tuple<unsigned short *, unsigned int *, float *>::move_from_types(unsigned short *&&, unsigned int *&&, float *&&, std::integer_sequence<int, 0, 1, 2>)::(anonymous class)::operator()<2, float *>' requested here 176 | (move_one(std::move(_types), std::integral_constant<int, _is>{}), ...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:43:45: note: in instantiation of function template specialization 'rfl::Tuple<unsigned short *, unsigned int *, float *>::move_from_types<0, 1, 2>' requested here 43 | constexpr Tuple(Types&&... _t) noexcept { move_from_types(std::move(_t)..., seq_); } | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:215:10: note: in instantiation of member function 'rfl::Tuple<unsigned short *, unsigned int *, float *>::Tuple' requested here 215 | return rfl::Tuple<std::decay_t<Types>...>(std::forward<Types>(_args)...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:69:1: note: in instantiation of function template specialization 'rfl::make_tuple<unsigned short *, unsigned int *, float *>' requested here 69 | RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS( | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:46:21: note: expanded from macro 'RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS' 46 | return rfl::make_tuple(&_refs...); \ | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:69:1: note: in instantiation of function template specialization 'rfl::internal::tuple_view_helper<3>::tuple_view(Pod &)::(anonymous class)::operator()<unsigned short, unsigned int, float>' requested here /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:45:14: note: expanded from macro 'RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS' 45 | return [](auto&... _refs) { \ | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:2824:44: note: (skipping 3 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all) 2824 | return tuple_view_helper<num_fields<T>>::tuple_view(_t); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/has_fields.hpp:62:23: note: in instantiation of template type alias 'ptr_tuple_t' requested here 62 | using TupleType = ptr_tuple_t<T>; | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/to_ptr_named_tuple.hpp:59:17: note: in instantiation of function template specialization 'rfl::internal::has_fields<Pod>' requested here 59 | if constexpr (has_fields<std::remove_cvref_t<T>>()) { | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../to_view.hpp:15:20: note: in instantiation of function template specialization 'rfl::internal::to_ptr_named_tuple<Pod &>' requested here 15 | return internal::to_ptr_named_tuple(_t); | ^ /Users/username/dev/private/projectname/main.cpp:124:10: note: in instantiation of function template specialization 'rfl::to_view<Pod>' requested here 124 | rfl::to_view(unused).apply([&](const auto& field) { | ^ /Users/username/dev/private/projectname/main.cpp:132:9: note: in instantiation of function template specialization 'get_packed_size<Pod>' requested here 132 | get_packed_size<Pod>() == | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:56:6: note: candidate function [with _Tp = float *] has been explicitly deleted 56 | _Tp* addressof(const _Tp&&) noexcept = delete; | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:22:80: note: candidate function [with _Tp = float *] not viable: expects an lvalue for 1st argument 22 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* addressof(_Tp& __x) _NOEXCEPT { | ^ ~~~~~~~~ In file included from /Users/username/dev/private/projectname/main.cpp:112: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl.hpp:10: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/AddStructName.hpp:6: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Field.hpp:8: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Literal.hpp:14: /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:174:25: error: call to deleted function 'addressof' 174 | std::construct_at(std::addressof(std::bit_cast<Type>(data_.data() + pos<_i>())), Type(std::move(_t))); | ^~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:176:6: note: in instantiation of function template specialization 'rfl::Tuple<unsigned short *, unsigned int *, float *>::move_from_types(unsigned short *&&, unsigned int *&&, float *&&, std::integer_sequence<int, 0, 1, 2>)::(anonymous class)::operator()<1, unsigned int *>' requested here 176 | (move_one(std::move(_types), std::integral_constant<int, _is>{}), ...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:43:45: note: in instantiation of function template specialization 'rfl::Tuple<unsigned short *, unsigned int *, float *>::move_from_types<0, 1, 2>' requested here 43 | constexpr Tuple(Types&&... _t) noexcept { move_from_types(std::move(_t)..., seq_); } | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:215:10: note: in instantiation of member function 'rfl::Tuple<unsigned short *, unsigned int *, float *>::Tuple' requested here 215 | return rfl::Tuple<std::decay_t<Types>...>(std::forward<Types>(_args)...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:69:1: note: in instantiation of function template specialization 'rfl::make_tuple<unsigned short *, unsigned int *, float *>' requested here 69 | RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS( | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:46:21: note: expanded from macro 'RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS' 46 | return rfl::make_tuple(&_refs...); \ | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:69:1: note: in instantiation of function template specialization 'rfl::internal::tuple_view_helper<3>::tuple_view(Pod &)::(anonymous class)::operator()<unsigned short, unsigned int, float>' requested here /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:45:14: note: expanded from macro 'RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS' 45 | return [](auto&... _refs) { \ | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:2824:44: note: (skipping 3 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all) 2824 | return tuple_view_helper<num_fields<T>>::tuple_view(_t); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/has_fields.hpp:62:23: note: in instantiation of template type alias 'ptr_tuple_t' requested here 62 | using TupleType = ptr_tuple_t<T>; | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/to_ptr_named_tuple.hpp:59:17: note: in instantiation of function template specialization 'rfl::internal::has_fields<Pod>' requested here 59 | if constexpr (has_fields<std::remove_cvref_t<T>>()) { | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../to_view.hpp:15:20: note: in instantiation of function template specialization 'rfl::internal::to_ptr_named_tuple<Pod &>' requested here 15 | return internal::to_ptr_named_tuple(_t); | ^ /Users/username/dev/private/projectname/main.cpp:124:10: note: in instantiation of function template specialization 'rfl::to_view<Pod>' requested here 124 | rfl::to_view(unused).apply([&](const auto& field) { | ^ /Users/username/dev/private/projectname/main.cpp:132:9: note: in instantiation of function template specialization 'get_packed_size<Pod>' requested here 132 | get_packed_size<Pod>() == | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:56:6: note: candidate function [with _Tp = unsigned int *] has been explicitly deleted 56 | _Tp* addressof(const _Tp&&) noexcept = delete; | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:22:80: note: candidate function [with _Tp = unsigned int *] not viable: expects an lvalue for 1st argument 22 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* addressof(_Tp& __x) _NOEXCEPT { | ^ ~~~~~~~~ In file included from /Users/username/dev/private/projectname/main.cpp:112: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl.hpp:10: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/AddStructName.hpp:6: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Field.hpp:8: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Literal.hpp:14: /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:174:25: error: call to deleted function 'addressof' 174 | std::construct_at(std::addressof(std::bit_cast<Type>(data_.data() + pos<_i>())), Type(std::move(_t))); | ^~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:176:6: note: in instantiation of function template specialization 'rfl::Tuple<unsigned short *, unsigned int *, float *>::move_from_types(unsigned short *&&, unsigned int *&&, float *&&, std::integer_sequence<int, 0, 1, 2>)::(anonymous class)::operator()<0, unsigned short *>' requested here 176 | (move_one(std::move(_types), std::integral_constant<int, _is>{}), ...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:43:45: note: in instantiation of function template specialization 'rfl::Tuple<unsigned short *, unsigned int *, float *>::move_from_types<0, 1, 2>' requested here 43 | constexpr Tuple(Types&&... _t) noexcept { move_from_types(std::move(_t)..., seq_); } | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:215:10: note: in instantiation of member function 'rfl::Tuple<unsigned short *, unsigned int *, float *>::Tuple' requested here 215 | return rfl::Tuple<std::decay_t<Types>...>(std::forward<Types>(_args)...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:69:1: note: in instantiation of function template specialization 'rfl::make_tuple<unsigned short *, unsigned int *, float *>' requested here 69 | RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS( | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:46:21: note: expanded from macro 'RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS' 46 | return rfl::make_tuple(&_refs...); \ | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:69:1: note: in instantiation of function template specialization 'rfl::internal::tuple_view_helper<3>::tuple_view(Pod &)::(anonymous class)::operator()<unsigned short, unsigned int, float>' requested here /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:45:14: note: expanded from macro 'RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS' 45 | return [](auto&... _refs) { \ | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:2824:44: note: (skipping 3 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all) 2824 | return tuple_view_helper<num_fields<T>>::tuple_view(_t); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/has_fields.hpp:62:23: note: in instantiation of template type alias 'ptr_tuple_t' requested here 62 | using TupleType = ptr_tuple_t<T>; | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/to_ptr_named_tuple.hpp:59:17: note: in instantiation of function template specialization 'rfl::internal::has_fields<Pod>' requested here 59 | if constexpr (has_fields<std::remove_cvref_t<T>>()) { | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../to_view.hpp:15:20: note: in instantiation of function template specialization 'rfl::internal::to_ptr_named_tuple<Pod &>' requested here 15 | return internal::to_ptr_named_tuple(_t); | ^ /Users/username/dev/private/projectname/main.cpp:124:10: note: in instantiation of function template specialization 'rfl::to_view<Pod>' requested here 124 | rfl::to_view(unused).apply([&](const auto& field) { | ^ /Users/username/dev/private/projectname/main.cpp:132:9: note: in instantiation of function template specialization 'get_packed_size<Pod>' requested here 132 | get_packed_size<Pod>() == | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:56:6: note: candidate function [with _Tp = unsigned short *] has been explicitly deleted 56 | _Tp* addressof(const _Tp&&) noexcept = delete; | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:22:80: note: candidate function [with _Tp = unsigned short *] not viable: expects an lvalue for 1st argument 22 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* addressof(_Tp& __x) _NOEXCEPT { | ^ ~~~~~~~~ In file included from /Users/username/dev/private/projectname/main.cpp:112: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl.hpp:10: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/AddStructName.hpp:6: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Field.hpp:8: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Literal.hpp:14: /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:174:25: error: call to deleted function 'addressof' 174 | std::construct_at(std::addressof(std::bit_cast<Type>(data_.data() + pos<_i>())), Type(std::move(_t))); | ^~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:176:6: note: in instantiation of function template specialization 'rfl::Tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::move_from_types(rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *> &&, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *> &&, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *> &&, std::integer_sequence<int, 0, 1, 2>)::(anonymous class)::operator()<2, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>' requested here 176 | (move_one(std::move(_types), std::integral_constant<int, _is>{}), ...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:43:45: note: in instantiation of function template specialization 'rfl::Tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::move_from_types<0, 1, 2>' requested here 43 | constexpr Tuple(Types&&... _t) noexcept { move_from_types(std::move(_t)..., seq_); } | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:215:10: note: in instantiation of member function 'rfl::Tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::Tuple' requested here 215 | return rfl::Tuple<std::decay_t<Types>...>(std::forward<Types>(_args)...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/NamedTuple.hpp:467:17: note: in instantiation of function template specialization 'rfl::make_tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>' requested here 467 | return rfl::make_tuple(wrap(Index<_is>{})..., _args...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/NamedTuple.hpp:207:45: note: in instantiation of function template specialization 'rfl::NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::make_fields<0, 1, 2>' requested here 207 | constexpr Fields fields() const& { return make_fields(seq_); } | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/NamedTuple.hpp:200:32: note: in instantiation of member function 'rfl::NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::fields' requested here 200 | rfl::apply(apply_to_field, fields()); | ^ /Users/username/dev/private/projectname/main.cpp:124:26: note: in instantiation of function template specialization 'rfl::NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::apply<(lambda at /Users/username/dev/private/projectname/main.cpp:124:32)>' requested here 124 | rfl::to_view(unused).apply([&](const auto& field) { | ^ /Users/username/dev/private/projectname/main.cpp:132:9: note: in instantiation of function template specialization 'get_packed_size<Pod>' requested here 132 | get_packed_size<Pod>() == | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:56:6: note: candidate function [with _Tp = rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>] has been explicitly deleted 56 | _Tp* addressof(const _Tp&&) noexcept = delete; | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:22:80: note: candidate function [with _Tp = rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>] not viable: expects an lvalue for 1st argument 22 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* addressof(_Tp& __x) _NOEXCEPT { | ^ ~~~~~~~~ In file included from /Users/username/dev/private/projectname/main.cpp:112: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl.hpp:10: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/AddStructName.hpp:6: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Field.hpp:8: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Literal.hpp:14: /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:174:25: error: call to deleted function 'addressof' 174 | std::construct_at(std::addressof(std::bit_cast<Type>(data_.data() + pos<_i>())), Type(std::move(_t))); | ^~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:176:6: note: in instantiation of function template specialization 'rfl::Tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::move_from_types(rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *> &&, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *> &&, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *> &&, std::integer_sequence<int, 0, 1, 2>)::(anonymous class)::operator()<1, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>>' requested here 176 | (move_one(std::move(_types), std::integral_constant<int, _is>{}), ...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:43:45: note: in instantiation of function template specialization 'rfl::Tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::move_from_types<0, 1, 2>' requested here 43 | constexpr Tuple(Types&&... _t) noexcept { move_from_types(std::move(_t)..., seq_); } | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:215:10: note: in instantiation of member function 'rfl::Tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::Tuple' requested here 215 | return rfl::Tuple<std::decay_t<Types>...>(std::forward<Types>(_args)...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/NamedTuple.hpp:467:17: note: in instantiation of function template specialization 'rfl::make_tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>' requested here 467 | return rfl::make_tuple(wrap(Index<_is>{})..., _args...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/NamedTuple.hpp:207:45: note: in instantiation of function template specialization 'rfl::NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::make_fields<0, 1, 2>' requested here 207 | constexpr Fields fields() const& { return make_fields(seq_); } | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/NamedTuple.hpp:200:32: note: in instantiation of member function 'rfl::NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::fields' requested here 200 | rfl::apply(apply_to_field, fields()); | ^ /Users/username/dev/private/projectname/main.cpp:124:26: note: in instantiation of function template specialization 'rfl::NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::apply<(lambda at /Users/username/dev/private/projectname/main.cpp:124:32)>' requested here 124 | rfl::to_view(unused).apply([&](const auto& field) { | ^ /Users/username/dev/private/projectname/main.cpp:132:9: note: in instantiation of function template specialization 'get_packed_size<Pod>' requested here 132 | get_packed_size<Pod>() == | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:56:6: note: candidate function [with _Tp = rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>] has been explicitly deleted 56 | _Tp* addressof(const _Tp&&) noexcept = delete; | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:22:80: note: candidate function [with _Tp = rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>] not viable: expects an lvalue for 1st argument 22 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* addressof(_Tp& __x) _NOEXCEPT { | ^ ~~~~~~~~ In file included from /Users/username/dev/private/projectname/main.cpp:112: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl.hpp:10: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/AddStructName.hpp:6: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Field.hpp:8: In file included from /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Literal.hpp:14: /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:174:25: error: call to deleted function 'addressof' 174 | std::construct_at(std::addressof(std::bit_cast<Type>(data_.data() + pos<_i>())), Type(std::move(_t))); | ^~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:176:6: note: in instantiation of function template specialization 'rfl::Tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::move_from_types(rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *> &&, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *> &&, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *> &&, std::integer_sequence<int, 0, 1, 2>)::(anonymous class)::operator()<0, rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>>' requested here 176 | (move_one(std::move(_types), std::integral_constant<int, _is>{}), ...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:43:45: note: in instantiation of function template specialization 'rfl::Tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::move_from_types<0, 1, 2>' requested here 43 | constexpr Tuple(Types&&... _t) noexcept { move_from_types(std::move(_t)..., seq_); } | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:215:10: note: in instantiation of member function 'rfl::Tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::Tuple' requested here 215 | return rfl::Tuple<std::decay_t<Types>...>(std::forward<Types>(_args)...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/NamedTuple.hpp:467:17: note: in instantiation of function template specialization 'rfl::make_tuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>' requested here 467 | return rfl::make_tuple(wrap(Index<_is>{})..., _args...); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/NamedTuple.hpp:207:45: note: in instantiation of function template specialization 'rfl::NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::make_fields<0, 1, 2>' requested here 207 | constexpr Fields fields() const& { return make_fields(seq_); } | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/NamedTuple.hpp:200:32: note: in instantiation of member function 'rfl::NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::fields' requested here 200 | rfl::apply(apply_to_field, fields()); | ^ /Users/username/dev/private/projectname/main.cpp:124:26: note: in instantiation of function template specialization 'rfl::NamedTuple<rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>, rfl::Field<internal::StringLiteral<4>{{"bar"}}, unsigned int *>, rfl::Field<internal::StringLiteral<4>{{"baz"}}, float *>>::apply<(lambda at /Users/username/dev/private/projectname/main.cpp:124:32)>' requested here 124 | rfl::to_view(unused).apply([&](const auto& field) { | ^ /Users/username/dev/private/projectname/main.cpp:132:9: note: in instantiation of function template specialization 'get_packed_size<Pod>' requested here 132 | get_packed_size<Pod>() == | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:56:6: note: candidate function [with _Tp = rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>] has been explicitly deleted 56 | _Tp* addressof(const _Tp&&) noexcept = delete; | ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/addressof.h:22:80: note: candidate function [with _Tp = rfl::Field<internal::StringLiteral<4>{{"foo"}}, unsigned short *>] not viable: expects an lvalue for 1st argument 22 | inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* addressof(_Tp& __x) _NOEXCEPT { | ^ ~~~~~~~~ /Users/username/dev/private/projectname/main.cpp:132:9: error: static assertion expression is not an integral constant expression 132 | get_packed_size<Pod>() == | ^~~~~~~~~~~~~~~~~~~~~~~~~ 133 | sizeof(std::uint16_t) + sizeof(std::uint32_t) + sizeof(float) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__bit/bit_cast.h:37:10: note: bit_cast to a pointer type is not allowed in a constant expression 37 | return __builtin_bit_cast(_ToType, __from); | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:174:40: note: in call to 'bit_cast<unsigned short *, unsigned char *>(this->data_.data() + pos<0>())' 174 | std::construct_at(std::addressof(std::bit_cast<Type>(data_.data() + pos<_i>())), Type(std::move(_t))); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:176:6: note: in call to 'move_one.operator()<0, unsigned short *>(&_refs, {})' 176 | (move_one(std::move(_types), std::integral_constant<int, _is>{}), ...); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:43:45: note: in call to 'this->move_from_types<0, 1, 2>(&_refs, &_refs, &_refs, {})' 43 | constexpr Tuple(Types&&... _t) noexcept { move_from_types(std::move(_t)..., seq_); } | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/Tuple.hpp:215:10: note: in call to 'Tuple(&_refs, &_refs, &_refs)' 215 | return rfl::Tuple<std::decay_t<Types>...>(std::forward<Types>(_args)...); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:69:1: note: in call to 'make_tuple<unsigned short *, unsigned int *, float *>(&_refs, &_refs, &_refs)' 69 | RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS( | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 70 | 3, f0, f1, f2); | ~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:46:16: note: expanded from macro 'RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS' 46 | return rfl::make_tuple(&_refs...); \ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:69:1: note: (skipping 3 calls in backtrace; use -fconstexpr-backtrace-limit=0 to see all) /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/bind_to_tuple.hpp:45:14: note: expanded from macro 'RFL_INTERNAL_TUPLE_VIEW_IF_YOU_SEE_AN_ERROR_REFER_TO_DOCUMENTATION_ON_C_ARRAYS' 45 | return [](auto&... _refs) { \ | ^ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/to_flattened_ptr_tuple.hpp:38:28: note: in call to 'to_ptr_tuple<Pod>(unused)' 38 | return flatten_ptr_tuple(to_ptr_tuple(_t)); | ^~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../internal/to_ptr_named_tuple.hpp:72:32: note: in call to 'to_flattened_ptr_tuple<Pod &>(unused)' 72 | auto flattened_ptr_tuple = to_flattened_ptr_tuple(_t); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/reflect-cpp/include/rfl/internal/../to_view.hpp:15:10: note: in call to 'to_ptr_named_tuple<Pod &>(unused)' 15 | return internal::to_ptr_named_tuple(_t); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/main.cpp:124:5: note: in call to 'to_view<Pod>(unused)' 124 | rfl::to_view(unused).apply([&](const auto& field) { | ^~~~~~~~~~~~~~~~~~~~ /Users/username/dev/private/projectname/main.cpp:132:9: note: in call to 'get_packed_size<Pod>()' 132 | get_packed_size<Pod>() == | ^~~~~~~~~~~~~~~~~~~~~~ 7 errors generated. [2/7] Building CXX object reflect-cpp/CMakeFiles/reflectcpp.dir/cmake_pch.hxx.pch ninja: build stopped: subcommand failed.
@saxbophone what we mean by "at compile time" is that the fields are resolved at compile time, not that the function itself is applied at compile time.
The difficulty is that the tuple implementation uses placement new, which makes it difficult to make this fully constexpr.
But I will take a look at what can be done for this particular use case.
what we mean by "at compile time" is that the fields are resolved at compile time, not that the function itself is applied at compile time.
I think I understand. Perhaps the docs could be clarified as the current wording is a bit confusing as to this nuance.
The difficulty is that the tuple implementation uses placement new, which makes it difficult to make this fully constexpr.
Yeah, I looked into replacing it with
std::construct_at(), but I couldn't get the casting of the first pointer argument to work. I was only rushing it, perhaps it can be done with a bit more care and time...But I will take a look at what can be done for this particular use case.
Much appreciated. I assume that at some point, reflect-cpp internally has access to the types of all the fields in the struct, as like a template parameter-pack or something similar (perhaps a variadic tuple)? If this could be exposed somehow in a way that could be accessed by client code, that would probably be enough for my needs...
@saxbophone C++ 26 offers a much simpler way to implement a non-recursive tuple. There isn't a lot of compiler support for it yet, but it might be the future.
In the docs on the README, the Reflective programming section suggests in the second example that
rfl::to_view()can be used to iterate over the fields at compile-time, with a relevant example usingview.apply(...)...However, I am unable to use it in a
constexprmethod forced to execute at compile-time, here is a contrived demo that reproduces the issue. It fails to compile because it complains thatrfl::to_view()cannot be used in a constant expression:As a counter-example, if one instead defines the function as non-constexpr, and uses
assert()instead ofstatic_assert(), then the program both compiles and runs successfully without any assertion failures:By the way, it would be nice if reflect-cpp provided a nicer way than this for me to iterate over all the fields of an object and get their types. The default-constructed variable
unusedis only provided here because I couldn't work out how else to ask reflect-cpp to iterate the fields of a struct for me without providing it with an object of that struct's type first. For my purposes, I only care about their types, not their values, in this context...I suspect the issue I am experiencing here might be highly related to that mentioned in #220, which if I'm not mistaken, also seems to rest on the inability for
rfl::to_view()to be used in a constant expression. I peeked at your function declarations and I noted thatrfl::to_view()and other functions it calls are not declaredconstexpr, that might be required since I don't thinkconstexprcan be deduced in general?