c++jsonboostboost-mp11

'value_from': no matching overloaded function found Project1


I am implementing a program,It can make a function call based on the given string.
The implementation is as follows:
it might be a bit long, here is the online version

#include<iostream>
#include<vector>
#include<string>
#include<stack>
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/json.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/string_view.hpp>
using namespace std;
using namespace boost::json;

// C1:class name
// C2:pointer to member function
// R:return type of member function
// A: member function parameter pack
// I: Parameter pack expansion
template<class C1, class C2, class R, class... A, std::size_t... I>
boost::json::value
call_impl_(C1& c1, R(C2::* pmf)(A...), boost::json::array const& args,
  std::index_sequence<I...>)
{
  return boost::json::value_from((c1.*pmf)(boost::json::value_to< boost::remove_cv_ref_t<A> >(args[I])...));
}
// C1: class name
// C2: pointer to member function
// R : return type of member function
// A : member function parameter pack
// args: member function args
template<class C1, class C2, class R, class... A>
boost::json::value
call_impl(C1& c1, R(C2::* pmf)(A...), boost::json::array const& args)
{
  if (args.size() != sizeof...(A))
    throw std::invalid_argument("Invalid number of arguments");
  return call_impl_(c1, pmf, args, std::index_sequence_for<A...>());
}
// c:class name
// method: member function name
// args: member function args
// 
template<class C>
boost::json::value call(C& c, boost::string_view method, boost::json::value const& args = boost::json::array{})
{
  using Fd = boost::describe::describe_members<C,
    boost::describe::mod_public | boost::describe::mod_function>;
  bool found = false;
  boost::json::value result;
  boost::mp11::mp_for_each<Fd>([&](auto D) {
    if (!found && method == D.name)
    {
      result = call_impl(c, D.pointer, args.as_array());
      found = true;
    }
    });
  if (!found)
  {
    throw std::invalid_argument("Invalid method name");
  }
  return result;
}
//    BOOST_DESCRIBE_CLASS(Solution, (), (member_func1, member_func2, member_func3), (), ());

class StackOfPlates {
  vector<stack<int>> store;
  int capacity;
public:
  StackOfPlates(int cap) {
    capacity = cap;
  }
  void push(int val) {
    if (capacity == 0)return;
    if (store.empty() || store.back().size() == capacity)
      store.emplace_back(stack<int>());
    store.back().push(val);
  }
  int pop() {
    if (capacity == 0 || store.empty())
      return -1;
    int res = store.back().top();
    store.back().pop();
    if (store.back().empty())
      store.pop_back();
    return res;
  }
  int popAtStack(int index) {
    if (capacity == 0 || index >= store.size() || store[index].empty())return -1;
    int res = store[index].top();
    store[index].pop();
    if (store[index].empty()) {
      store.erase(store.begin() + index);
    }
    return res;
  }
  BOOST_DESCRIBE_CLASS(StackOfPlates, (), (push, pop, popAtStack), (), ())
};

int main()
{
  vector<std::string> t1{ "push", "push", "popAt", "pop", "pop" };
  vector<vector<int>> t2{ { 1},{2},{1},{},{} };
  StackOfPlates obj(1);// (init1, init2);
  for (int i = 0; i < t1.size(); ++i)
  {
    std::string sa = t1[i];
    std::vector<int> sb = t2[i];
    boost::json::value sc = boost::json::value_from(sb);
    std::cout << call(obj, sa, sc) << std::endl;
  }
  return 0;
}

The library that needs to be installed is boost 1.80
Thecall_impl relevant code comes from the boost documentation
development environment is windows11/ Visual Studio 2022 (v143)
The error message is:

Severity    Code    Description Project File    Line    Suppression State
Error   C2672   'value_from': no matching overloaded function found Project1    C:\Users\mingy\source\repos\Project1\Project1\main.cpp  26  

output:

>main.cpp
1>C:\Users\mingy\source\repos\Project1\Project1\main.cpp(26,23): error C2672: 'value_from': no matching overloaded function found
1>C:\dev\vcpkg\installed\x64-windows\include\boost\json\value_from.hpp(125,1): message : could be 'void boost::json::value_from(T &&,boost::json::value &)'
1>C:\Users\mingy\source\repos\Project1\Project1\main.cpp(26,23): message : 'void boost::json::value_from(T &&,boost::json::value &)': expects 2 arguments - 1 provided
1>C:\dev\vcpkg\installed\x64-windows\include\boost\json\value_from.hpp(125): message : see declaration of 'boost::json::value_from'
1>C:\dev\vcpkg\installed\x64-windows\include\boost\json\value_from.hpp(83,1): message : or       'boost::json::value boost::json::value_from(T &&,boost::json::storage_ptr)'
1>C:\Users\mingy\source\repos\Project1\Project1\main.cpp(26,23): message : Failed to specialize function template 'boost::json::value boost::json::value_from(T &&,boost::json::storage_ptr)'
1>C:\dev\vcpkg\installed\x64-windows\include\boost\json\value_from.hpp(83): message : see declaration of 'boost::json::value_from'
1>C:\Users\mingy\source\repos\Project1\Project1\main.cpp(25,1): message : With the following template arguments:
1>C:\Users\mingy\source\repos\Project1\Project1\main.cpp(25,1): message : 'T=R'
1>C:\Users\mingy\source\repos\Project1\Project1\main.cpp(36): message : see reference to function template instantiation 'boost::json::value call_impl_<C1,StackOfPlates,R,int,0>(C1 &,R (__cdecl StackOfPlates::* )(int),const boost::json::array &,std::integer_sequence<size_t,0>)' being compiled
1>        with
1>        [
1>            C1=StackOfPlates,
1>            R=void
1>        ]
1>C:\Users\mingy\source\repos\Project1\Project1\main.cpp(47): message : see reference to function template instantiation 'boost::json::value call_impl<C,StackOfPlates,void,int>(C1 &,R (__cdecl StackOfPlates::* )(int),const boost::json::array &)' being compiled
1>        with
1>        [
1>            C=StackOfPlates,
1>            C1=StackOfPlates,
1>            R=void
1>        ]
1>C:\dev\vcpkg\installed\x64-windows\include\boost\mp11\algorithm.hpp(1037): message : see reference to function template instantiation 'void call::<lambda_1>::operator ()<boost::describe::detail::member_descriptor<boost_public_member_descriptor_fn::<lambda_1>::()::_boost_desc,1>>(_T1) const' being compiled
1>        with
1>        [
1>            _T1=boost::describe::detail::member_descriptor<boost_public_member_descriptor_fn::<lambda_1>::()::_boost_desc,1>
1>        ]
1>C:\dev\vcpkg\installed\x64-windows\include\boost\mp11\algorithm.hpp(1054): message : see reference to function template instantiation 'F boost::mp11::detail::mp_for_each_impl<boost::describe::detail::member_descriptor<boost_public_member_descriptor_fn::<lambda_1>::()::_boost_desc,1>,boost::describe::detail::member_descriptor<boost_public_member_descriptor_fn::<lambda_2>::()::_boost_desc,1>,boost::describe::detail::member_descriptor<boost_public_member_descriptor_fn::<lambda_3>::()::_boost_desc,1>,_Ty>(boost::mp11::mp_list<boost::describe::detail::member_descriptor<boost_public_member_descriptor_fn::<lambda_1>::()::_boost_desc,1>,boost::describe::detail::member_descriptor<boost_public_member_descriptor_fn::<lambda_2>::()::_boost_desc,1>,boost::describe::detail::member_descriptor<boost_public_member_descriptor_fn::<lambda_3>::()::_boost_desc,1>>,F &&)' being compiled
1>        with
1>        [
1>            F=call::<lambda_1>,
1>            _Ty=call::<lambda_1>
1>        ]
1>C:\Users\mingy\source\repos\Project1\Project1\main.cpp(47): message : see reference to function template instantiation 'call::<lambda_1> boost::mp11::mp_for_each<Fd,call::<lambda_1>>(F &&)' being compiled
1>        with
1>        [
1>            F=call::<lambda_1>
1>        ]
1>C:\Users\mingy\source\repos\Project1\Project1\main.cpp(116): message : see reference to function template instantiation 'boost::json::value call<StackOfPlates>(C &,boost::string_view,const boost::json::value &)' being compiled
1>        with
1>        [
1>            C=StackOfPlates
1>        ]
1>Done building project "Project1.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

When I was using boost1.78 it worked fine, today I reinstalled boost 1.80 and got this kind of error. I'm not very familiar with mp11, so I can't understand it.
Can someone explain what the problem is and how can I fix it?

I once asked a question related to this


Solution

  • Compiling your code with GCC gives:

    <source>:18:18: error: invalid use of void expression
       18 |         (c1.*pmf)(json::value_to<boost::remove_cv_ref_t<A>>(args[I])...));https://godbolt.org/z/E7h4M7bjE
    

    It makes sense because you "reflect" the push member function which returns void. The simplest you can do is to make it return something:

    bool push(int val) {
        if (capacity == 0)
            return false;
        if (store.empty() || store.back().size() == capacity)
            store.emplace_back();
        store.back().push(val);
        return true;
    }
    

    Now you have more luck with that Boost Describe sample code: https://godbolt.org/z/xbcT3jda1

    Fixing The Style

    Apart from the non-existent popAt method name, fixing some fallout like:

    Live On Coliru

    #include <boost/describe.hpp>
    #include <boost/json/src.hpp> // for header-only
    #include <boost/mp11.hpp>
    #include <boost/type_traits.hpp>
    #include <boost/utility/string_view.hpp>
    #include <iostream>
    #include <stack>
    #include <string>
    #include <vector>
    
    namespace json = boost::json;
    
    namespace RPC {
        template <class C1, class C2, class R, class... A, std::size_t... I>
        json::value call_impl_( //
            C1& c1, R (C2::*pmf)(A...), json::array const& args,
            std::index_sequence<I...>) //
        {
            return json::value_from(
                (c1.*pmf)(json::value_to<boost::remove_cv_ref_t<A>>(args[I])...));
        }
    
        template <class C1, class C2, class R, class... A>
        json::value call_impl(                                   //
            C1& c1, R (C2::*pmf)(A...), json::array const& args) //
        {
            if (args.size() != sizeof...(A))
                throw std::invalid_argument("Invalid number of arguments");
            return call_impl_(c1, pmf, args, std::index_sequence_for<A...>());
        }
    
        template <class C>
        json::value call(C& c, boost::string_view method,
                         json::value const& args = json::array{}) //
        {
            namespace bd = boost::describe;
            using Fd = bd::describe_members<C, bd::mod_public | bd::mod_function>;
    
            bool        found = false;
            json::value result;
            boost::mp11::mp_for_each<Fd>([&](auto D) {
                if (!found && method == D.name) {
                    result = call_impl(c, D.pointer, args.as_array());
                    found  = true;
                }
            });
    
            return found ? result
                         : throw std::invalid_argument("Invalid method name");
        }
    } // namespace RPC
    
    class StackOfPlates {
        using Stack = std::stack<int>;
        std::vector<Stack> store;
        size_t             capacity;
    
      public:
        StackOfPlates(size_t cap) { capacity = cap; }
    
        bool push(int val) {
            if (capacity == 0)
                return false;
            if (store.empty() || store.back().size() == capacity)
                store.emplace_back();
            store.back().push(val);
            return true;
        }
    
        int pop() {
            if (capacity == 0 || store.empty())
                return -1;
            int res = store.back().top();
            store.back().pop();
            if (store.back().empty())
                store.pop_back();
            return res;
        }
    
        int popAtStack(size_t index) {
            if (capacity == 0 || index >= store.size() || store.at(index).empty())
                return -1;
            int res = store.at(index).top();
            store.at(index).pop();
            if (store.at(index).empty()) {
                store.erase(store.begin() + index);
            }
            return res;
        }
        BOOST_DESCRIBE_CLASS(StackOfPlates, (), (push, pop, popAtStack), (), ())
    };
    
    int main() {
        struct {
            std::string method;
            json::array args;
        } actions[]{
            {"push", {1}}, {"push", {2}}, {"popAtStack", {1}},
            {"pop", {}},   {"pop", {}},
        };
    
        // std::vector init1{1, 1, 2, 2, 2, 3}, init2{1, 4, 5, 2, 5, 4};
        StackOfPlates obj(1); // (init1, init2);
    
        for (auto& [method, args] : actions)
            std::cout << "RPC Call: " << method << args << " -> "
                      << RPC::call(obj, method, args) << std::endl;
    }
    

    Prints

    RPC Call: push[1] -> true
    RPC Call: push[2] -> true
    RPC Call: popAtStack[1] -> 2
    RPC Call: pop[] -> 1
    RPC Call: pop[] -> -1
    

    See also Compiler explorer GCC, Clang and MSVC

    UPDATE

    Alternatively you can make the call_impl_ deal with void return types, of course:

    if constexpr (std::is_same_v<R, void>) {
        (c1.*pmf)(json::value_to<boost::remove_cv_ref_t<A>>(args[I])...);
        return json::value{};
    } else {
        return json::value_from((c1.*pmf)(
            json::value_to<boost::remove_cv_ref_t<A>>(args[I])...));
    }
    

    See it live as well: GCC, Clang and MSVC