veselink1 / refl-cpp

Static reflection for C++17 (compile-time enumeration, attributes, proxies, overloads, template functions, metaprogramming).
https://veselink1.github.io/refl-cpp/md__introduction.html
MIT License
1.05k stars 76 forks source link

Another Compiler error on Visual Studio 2019 but not on XCode (GCC) #54

Closed rpatters1 closed 2 years ago

rpatters1 commented 2 years ago

This is a followup to issue #52. If that issue is resolved (by applying the change in pull request #53), then this problem arises. For some reason, the compiler is unhappy with any kind of capture in the nested lamda. As mentioned in the title, this code compiles and runs correctly on XCode/GCC.

struct foo {
   int _bar;
   int get_bar() const {return _bar;}
   void set_bar(int val) {_bar = val;}
};
REFL_AUTO
(
   type(foo),
   func(get_bar, property()),
   func(set_bar, property())
)
template<class T>
static void ProcessClass()
{
   constexpr auto type = refl::reflect<T>();
   constexpr auto members = get_members(type);

   for_each(members, [&](auto member)
   {
      if constexpr (refl::descriptor::is_property(member) && !refl::descriptor::is_writable(member))
      {
         constexpr auto propertyName = refl::descriptor::get_display_name_const(member);
         constexpr auto setters = filter(get_members(refl::reflect<T>()), [&propertyName](auto chkMember) {
            if constexpr (!refl::descriptor::is_property(chkMember) || !refl::descriptor::is_writable(chkMember))
               return false;
            constexpr auto candidateName = refl::descriptor::get_display_name_const(chkMember);
            // This line generates C2131 expression did not evaluate to a constant (in Visual Studio 2019)
            // Comment it out and the code compiles
            if constexpr (propertyName == candidateName) return true;
            return false;
            });
      }
   });
}
static void my_runtime_func()
{
   ProcessClass<foo>();
}

The full error log is here:

1>C:\myprogram\myprogram.cpp(160,40): error C2131: expression did not evaluate to a constant
1>C:\myprogram\myprogram.cpp(160,27): message : failure was caused by a read of a variable outside its lifetime
1>C:\myprogram\myprogram.cpp(160,27): message : see usage of 'this'
1>C:\myprogram\refl-cpp\include\refl.hpp(1717): message : see reference to function template instantiation 'bool ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>::operator ()<T>(T) const' being compiled
1>        with
1>        [
1>            T=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1717): message : see reference to function template instantiation 'auto refl::util::detail::filter<_Ty,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>,>(F,refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,refl::util::type_list<>)' being compiled
1>        with
1>        [
1>            _Ty=ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>,
1>            T=foo,
1>            F=ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>
1>        ]
1>C:\myprogram\myprogram.cpp(162): message : see reference to function template instantiation 'auto refl::util::filter<ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,F &&)' being compiled
1>        with
1>        [
1>            T=foo,
1>            F=ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1558): message : see reference to function template instantiation 'auto ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::operator ()<_Ty>(_Ty) const' being compiled
1>        with
1>        [
1>            _Ty=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1552): message : see reference to function template instantiation 'auto refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>::operator ()<_Ty>(_Ty &&,size_t) const' being compiled
1>        with
1>        [
1>            _Ty=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1602): message : see reference to function template instantiation 'auto refl::util::detail::eval_in_order_to_tuple<_Ty,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>,0,1,>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,std::integer_sequence<size_t,0,1>,F &&)' being compiled
1>        with
1>        [
1>            _Ty=refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>,
1>            T=foo,
1>            F=refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1635): message : see reference to function template instantiation 'auto refl::util::map_to_tuple<refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,F &&)' being compiled
1>        with
1>        [
1>            T=foo,
1>            F=refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>
1>        ]
1>C:\myprogram\myprogram.cpp(164): message : see reference to function template instantiation 'void refl::util::for_each<ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,F &&)' being compiled
1>        with
1>        [
1>            T=foo,
1>            F=ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>
1>        ]
1>C:\myprogram\myprogram.cpp(168): message : see reference to function template instantiation 'void ProcessClass<foo>(void)' being compiled
1>C:\myprogram\refl-cpp\include\refl.hpp(1695,32): error C2131: expression did not evaluate to a constant
1>C:\myprogram\refl-cpp\include\refl.hpp(1695,32): message : failure was caused by call of undefined function or one not declared 'constexpr'
1>C:\myprogram\refl-cpp\include\refl.hpp(1695,32): message : see usage of 'ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>::operator ()'
1>C:\myprogram\refl-cpp\include\refl.hpp(1693,13): error C3487: 'refl::util::type_list<>': all return expressions must deduce to the same type: previously it was 'refl::util::type_list<refl::descriptor::function_descriptor<T,1>>'
1>        with
1>        [
1>            T=foo
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1699,34): error C2440: 'return': cannot convert from 'refl::util::type_list<>' to 'refl::util::type_list<refl::descriptor::function_descriptor<T,1>>'
1>        with
1>        [
1>            T=foo
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1699,34): message : No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
veselink1 commented 2 years ago

As the error message suggests, the condition propertyName == candidateName cannot be evaulated at compile time, because candidateName is captured by reference. Try to capture the name or member by value and use that.

I understand that there is a difference in the behaviour of MSVC and gcc, but this is not something that I can fix in refl-cpp. (I believe MSVC actually implements this correctly and that this is forbidden by C++17/20.) \

Sorry, I am closing this now, but thanks for reporting it!

rpatters1 commented 2 years ago

I was basically trying to implement my own get_writer so in a way refl-cpp did address it.