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
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
Apart from the non-existent popAt
method name, fixing some fallout like:
.at(idx)
in favor of .operator[](idx)
because I wouldn't vouch for your logic to be correct :)using namespace
#ifdef design
into namespace RPC
#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
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])...));
}