getml / reflect-cpp

A C++20 library for fast serialization, deserialization and validation using reflection. Supports JSON, BSON, CBOR, flexbuffers, msgpack, TOML, XML, YAML / msgpack.org[C++20]
https://getml.github.io/reflect-cpp/
MIT License
821 stars 65 forks source link

Adds r-value overloads for monadic operations in rfl::Result #47

Closed Onlynagesha closed 2 months ago

Onlynagesha commented 6 months ago

Changes:

  1. Adds r-value overloads for monadic operations in rfl::Result, i.e. rfl::Result<T>::and_then(const F&) && and rfl::Result<T>::and_then(const F&) const && etc.
  2. Adds operator-> for rfl::Result and rfl::Validator
liuzicheng1987 commented 6 months ago

@Onlynagesha , thanks for the contribution. I have a question, though: Could you point me to something that didn't work before the r-value overloads that works now?

As you can see, most of our tests involve items that cannot be copied, such as std::unique_ptr or rfl::Box. If the results weren't moved already, then most of our tests wouldn't compile. Could you explain what problem you are solving with the r-value overloads? Could you maybe provide a test that doesn't compile without the r-value overloads, but compiles once you do add them?

(I am not trying to be snarky or anything, I am honestly curious.)

Onlynagesha commented 6 months ago

@liuzicheng1987 The issue was found when I attempted to use rfl::Result as an alternative to C++23 std::expected. As shown in the example above, it's impossible to modify foo inside the lambda function via a left-reference before this commit, which is inconsistent to the behavior of std::expected.

#include <chrono>
#include <expected>
#include <fmt/color.h>
#include <iostream>
#include <rfl/Result.hpp>

struct VeryLarge {
  static inline auto default_ctor_count = 0;

  VeryLarge() : value(std::to_string(default_ctor_count++)) {
    std::cout << "Default constructor: VeryLarge()\n";
  }
  VeryLarge(VeryLarge&& other) noexcept : value(std::move(other.value)) {
    std::cout << fmt::format(fg(fmt::color::yellow), "Move constructor: VeryLarge(VeryLarge&&)\n");
    other.value = "(Moved away)";
  }
  VeryLarge(const VeryLarge& other) : value(other.value) {
    std::cout << fmt::format(fg(fmt::color::orange), "Copy constructor: VeryLarge(const VeryLarge&)\n");
  }

  std::string value;
};

// Expects consistent behavior.
template <class T>
using ResultType = rfl::Result<T>;
// using ResultType = std::expected<T, rfl::Error>;

auto some_func() -> ResultType<VeryLarge> {
  return VeryLarge{};
}

int main() {
  auto foo = some_func();
  std::cout << fmt::format("Before foo.and_then(): foo.value = {:?}\n", (*foo).value);
  // Here we attempt to modify the contents inside foo via a left-reference.
  foo.and_then([](VeryLarge& obj) -> ResultType<rfl::Nothing> {
    obj.value += "-modified"; // Modification here
    std::cout << fmt::format("foo.and_then(): obj.value: {:?}\n", obj.value);
    return rfl::Nothing{};
  });
  // We expect that the modification above is represented here.
  std::cout << fmt::format("After foo.and_then(): foo.value: {:?}\n", (*foo).value);

  // Still, for right-values, copy constructor shall not be triggered.
  some_func().and_then([](VeryLarge obj) -> ResultType<rfl::Nothing> {
    std::cout << fmt::format("some_func().and_then(): obj.value: {:?}\n", obj.value);
    return rfl::Nothing{};
  });

  return 0;
}
liuzicheng1987 commented 6 months ago

Hi @Onlynagesha ,

sorry it took me a couple of days to get back to you. I was a bit busy with the BSON integration.

Two things:

  1. I tried compiling the tests as described in the README, but they don't compile on GCC (possibly clang as well):
In file included from /home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/AllOf.hpp:4,
                 from /home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl.hpp:10,
                 from /home/ubuntu/PRs/onlynagesha/reflect-cpp/tests/json/test_one_of.cpp:4:
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Result.hpp: In instantiation of ‘rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)> [with TOrError = rfl::Error]’:
/usr/include/c++/11/bits/invoke.h:61:36:   required from ‘constexpr _Res std::__invoke_impl(std::__invoke_other, _Fn&&, _Args&& ...) [with _Res = rfl::Result<unsigned int>; _Fn = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Args = {rfl::Error&}]’
/usr/include/c++/11/bits/invoke.h:96:40:   required from ‘constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...) [with _Callable = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Args = {rfl::Error&}; typename std::__invoke_result<_Functor, _ArgTypes>::type = rfl::Result<unsigned int>]’
/usr/include/c++/11/variant:1016:24:   required from ‘static constexpr decltype(auto) std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...)>, std::integer_sequence<long unsigned int, __indices ...> >::__visit_invoke(_Visitor&&, _Variants ...) [with _Result_type = std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >; _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Variants = {std::variant<unsigned int, rfl::Error>&}; long unsigned int ...__indices = {1}]’
/usr/include/c++/11/variant:1032:28:   required from ‘static constexpr auto std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...)>, std::integer_sequence<long unsigned int, __indices ...> >::_S_apply() [with _Result_type = std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >; _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Variants = {std::variant<unsigned int, rfl::Error>&}; long unsigned int ...__indices = {1}]’
/usr/include/c++/11/variant:968:56:   required from ‘static constexpr void std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...), __dimensions ...>, std::integer_sequence<long unsigned int, _Idxs ...> >::_S_apply_single_alt(_Tp&, _Tp*) [with bool __do_cookie = false; long unsigned int __index = 1; _Tp = std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> > (*)(const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&, std::variant<unsigned int, rfl::Error>&)>; _Result_type = std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >; _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; long unsigned int ...__dimensions = {2}; _Variants = {std::variant<unsigned int, rfl::Error>&}; long unsigned int ...__indices = {}]’
/usr/include/c++/11/variant:947:48:   required from ‘constexpr const _Array_type std::__detail::__variant::__gen_vtable<std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >, const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&, std::variant<unsigned int, rfl::Error>&>::_S_vtable’
/usr/include/c++/11/variant:1724:45:   required from ‘constexpr decltype(auto) std::__do_visit(_Visitor&&, _Variants&& ...) [with _Result_type = std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >; _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Variants = {std::variant<unsigned int, rfl::Error>&}]’
/usr/include/c++/11/variant:1761:34:   required from ‘constexpr std::__detail::__variant::__visit_result_t<_Visitor, _Variants ...> std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Variants = {std::variant<unsigned int, rfl::Error>&}; std::__detail::__variant::__visit_result_t<_Visitor, _Variants ...> = rfl::Result<unsigned int>]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Result.hpp:267:22:   required from ‘rfl::Result<T> rfl::Result<T>::or_else(const F&) & [with F = rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>; T = unsigned int]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/OneOf.hpp:42:17:   required from ‘static rfl::Result<U> rfl::OneOf<C, Cs>::validate_impl(const T&, std::vector<rfl::Error>) [with T = unsigned int; Head = rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >; Tail = {rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> >}; C = rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >; Cs = {rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> >}]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/OneOf.hpp:17:38:   required from ‘static rfl::Result<U> rfl::OneOf<C, Cs>::validate(const T&) [with T = unsigned int; C = rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >; Cs = {rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> >}]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Validator.hpp:50:33:   required from ‘rfl::Validator<T, V, Vs>::Validator(U&&) [with U = int; typename std::enable_if<is_convertible_v<U, T>, bool>::type <anonymous> = true; T = unsigned int; V = rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >; Vs = {}]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/tests/json/test_one_of.cpp:29:70:   required from here
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Result.hpp:262:18: error: no match for call to ‘(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>) (rfl::Error&)’
  262 |         return _f(_t_or_err);
      |                ~~^~~~~~~~~~~
In file included from /home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl.hpp:18,
                 from /home/ubuntu/PRs/onlynagesha/reflect-cpp/tests/json/test_one_of.cpp:4:
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/OneOf.hpp:36:28: note: candidate: ‘rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>’ (near match)
   36 |     const auto push_back = [&](Error&& _err) -> rfl::Result<T> {
      |                            ^
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/OneOf.hpp:36:28: note:   conversion of argument 1 would be ill-formed:
In file included from /home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/AllOf.hpp:4,
                 from /home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl.hpp:10,
                 from /home/ubuntu/PRs/onlynagesha/reflect-cpp/tests/json/test_one_of.cpp:4:
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Result.hpp:262:18: error: cannot bind rvalue reference of type ‘rfl::Error&&’ to lvalue of type ‘rfl::Error’
  262 |         return _f(_t_or_err);
      |                ~~^~~~~~~~~~~
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Result.hpp: In instantiation of ‘rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)> [with TOrError = rfl::Error]’:
/usr/include/c++/11/bits/invoke.h:61:36:   required from ‘constexpr _Res std::__invoke_impl(std::__invoke_other, _Fn&&, _Args&& ...) [with _Res = rfl::Result<unsigned int>; _Fn = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Args = {rfl::Error&}]’
/usr/include/c++/11/bits/invoke.h:96:40:   required from ‘constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...) [with _Callable = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Args = {rfl::Error&}; typename std::__invoke_result<_Functor, _ArgTypes>::type = rfl::Result<unsigned int>]’
/usr/include/c++/11/variant:1016:24:   required from ‘static constexpr decltype(auto) std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...)>, std::integer_sequence<long unsigned int, __indices ...> >::__visit_invoke(_Visitor&&, _Variants ...) [with _Result_type = std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >; _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Variants = {std::variant<unsigned int, rfl::Error>&}; long unsigned int ...__indices = {1}]’
/usr/include/c++/11/variant:1032:28:   required from ‘static constexpr auto std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...)>, std::integer_sequence<long unsigned int, __indices ...> >::_S_apply() [with _Result_type = std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >; _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Variants = {std::variant<unsigned int, rfl::Error>&}; long unsigned int ...__indices = {1}]’
/usr/include/c++/11/variant:968:56:   required from ‘static constexpr void std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<_Result_type (*)(_Visitor, _Variants ...), __dimensions ...>, std::integer_sequence<long unsigned int, _Idxs ...> >::_S_apply_single_alt(_Tp&, _Tp*) [with bool __do_cookie = false; long unsigned int __index = 1; _Tp = std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> > (*)(const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&, std::variant<unsigned int, rfl::Error>&)>; _Result_type = std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >; _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; long unsigned int ...__dimensions = {2}; _Variants = {std::variant<unsigned int, rfl::Error>&}; long unsigned int ...__indices = {}’
/usr/include/c++/11/variant:947:48:   required from ‘constexpr const _Array_type std::__detail::__variant::__gen_vtable<std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >, const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&, std::variant<unsigned int, rfl::Error>&>::_S_vtable’
/usr/include/c++/11/variant:1724:45:   required from ‘constexpr decltype(auto) std::__do_visit(_Visitor&&, _Variants&& ...) [with _Result_type = std::__detail::__variant::__deduce_visit_result<rfl::Result<unsigned int> >; _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Variants = {std::variant<unsigned int, rfl::Error>&}]’
/usr/include/c++/11/variant:1761:34:   required from ‘constexpr std::__detail::__variant::__visit_result_t<_Visitor, _Variants ...> std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = const rfl::Result<unsigned int>::or_else<rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)> >(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>&) &::<lambda(TOrError&)>&; _Variants = {std::variant<unsigned int, rfl::Error>&}; std::__detail::__variant::__visit_result_t<_Visitor, _Variants ...> = rfl::Result<unsigned int>]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Result.hpp:267:22:   required from ‘rfl::Result<T> rfl::Result<T>::or_else(const F&) & [with F = rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>; T = unsigned int]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/OneOf.hpp:42:17:   required from ‘static rfl::Result<U> rfl::OneOf<C, Cs>::validate_impl(const T&, std::vector<rfl::Error>) [with T = unsigned int; Head = rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> >; Tail = {}; C = rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >; Cs = {rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> >}]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/OneOf.hpp:50:41:   required from ‘static rfl::Result<U> rfl::OneOf<C, Cs>::validate_impl(const T&, std::vector<rfl::Error>) [with T = unsigned int; Head = rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >; Tail = {rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> >}; C = rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >; Cs = {rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> >}]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/OneOf.hpp:17:38:   required from ‘static rfl::Result<U> rfl::OneOf<C, Cs>::validate(const T&) [with T = unsigned int; C = rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >; Cs = {rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> >}]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Validator.hpp:50:33:   required from ‘rfl::Validator<T, V, Vs>::Validator(U&&) [with U = int; typename std::enable_if<is_convertible_v<U, T>, bool>::type <anonymous> = true; T = unsigned int; V = rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >; Vs = {}]’
/home/ubuntu/PRs/onlynagesha/reflect-cpp/tests/json/test_one_of.cpp:29:70:   required from here
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Result.hpp:262:18: error: no match for call to ‘(const rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>) (rfl::Error&)’
In file included from /home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl.hpp:18,
                 from /home/ubuntu/PRs/onlynagesha/reflect-cpp/tests/json/test_one_of.cpp:4:
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/OneOf.hpp:36:28: note: candidate: ‘rfl::OneOf<rfl::AllOf<rfl::Minimum<0>, rfl::Maximum<10> >, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >::validate_impl<unsigned int, rfl::AllOf<rfl::Minimum<40>, rfl::Maximum<130> > >(const unsigned int&, std::vector<rfl::Error>)::<lambda(rfl::Error&&)>’ (near match)
   36 |     const auto push_back = [&](Error&& _err) -> rfl::Result<T> {
      |                            ^
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/OneOf.hpp:36:28: note:   conversion of argument 1 would be ill-formed:
In file included from /home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/AllOf.hpp:4,
                 from /home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl.hpp:10,
                 from /home/ubuntu/PRs/onlynagesha/reflect-cpp/tests/json/test_one_of.cpp:4:
/home/ubuntu/PRs/onlynagesha/reflect-cpp/include/rfl/Result.hpp:262:18: error: cannot bind rvalue reference of type ‘rfl::Error&&’ to lvalue of type ‘rfl::Error’
  262 |         return _f(_t_or_err);
      |                ~~^~~~~~~~~~~

Could you take a look at this?

  1. I think you have written a very good motivating example that demonstrates why your PR is useful. Could maybe add that as a test? (Just for JSON.)

Again, thank you for your contribution and sorry it took me so long to get back to you on this.

liuzicheng1987 commented 4 months ago

Hi @Onlynagesha , the compilation here still fails...could you take a look?