I'm invoking some user-defined callables with arguments determined at runtime. I have the following working:
using argument_t = std::variant< int, bool, double, std::string >;
using argument_list = std::vector< argument_t >;
template < typename Callable, std::size_t... S >
auto invoke_with_args_impl( Callable&& method, const argument_list& args, std::index_sequence< S... > )
{
return std::invoke( method, args[S]... );
}
template < std::size_t size, typename Callable >
auto invoke_with_args_impl( Callable&& method, const argument_list& args )
{
if ( args.size() != size )
{
throw std::runtime_error( "argument count mismatch" );
}
return invoke_with_args_impl( std::forward< Callable >( method ), args, std::make_index_sequence< size >() );
}
template < typename Callable >
auto invoke_with_args( Callable&& method, const argument_list& args )
{
switch ( args.size() )
{
case 0:
return method();
case 1:
return invoke_with_args_impl< 1 >( std::forward< Callable >( method ), args );
//.... ad nauseam
This all works fine, however, argument_t
must be the type of all the arguments in the user-defined function for it to work successfully.
I am trying to figure out how to pass the current alternative type of the variant instead.
Something like
return std::invoke( method, std::get< args[S].index() >( args[S] )... );
but obviously that doesn't work...unfortunately I'm at the end of my skills on this one.
How can this be done?
You might use something like:
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
template < typename Callable, std::size_t... Is >
auto invoke_with_args_impl(Callable&& method,
const argument_list& args,
std::index_sequence<Is...>)
{
return std::visit(overloaded{
[&](auto&&... ts)
-> decltype(std::invoke(method, static_cast<decltype(ts)>(ts)...))
{ return std::invoke(method, static_cast<decltype(ts)>(ts)...); },
[](auto&&... ts)
-> std::enable_if_t<!std::is_invocable<Callable, decltype(ts)...>::value>
{ throw std::runtime_error("Invalid arguments"); } // fallback
},
args[Is]...);
}