beliebige anzahl argumente weiterleiten mit type erasure



  • hi,

    folgender code:

    #include <utility>
    #include <cmath>
    #include <memory>
    #include <type_traits>
    #include <functional>
    #include <map>
    #include <initializer_list>
    #include <iostream>
    
    using arg_t = double;
    
    struct callable_t
    {
    	virtual ~callable_t() = default;
    	virtual arg_t invoke( arg_t const* args ) const = 0;
    };
    template< typename T >
    class one_arg_t : public callable_t
    {
    	T m_obj;
    
    public:
    	template< typename... args_t >
    	one_arg_t( args_t&&... args )
    		: m_obj( std::forward< args_t >( args )... )
    	{
    	}
    
    	virtual arg_t invoke( arg_t const* args ) const override
    	{
    		return m_obj( args[0] );
    	}
    };
    template< typename T >
    auto make_one_arg( T&& obj )
    {
    	return std::move( std::make_unique< one_arg_t< std::decay_t< T > > >( std::forward< T >( obj ) ) );
    }
    template< typename T >
    class two_args_t : public callable_t
    {
    	T m_obj;
    
    public:
    	template< typename... args_t >
    	two_args_t( args_t&&... args )
    		: m_obj( std::forward< args_t >( args )... )
    	{
    	}
    
    	virtual arg_t invoke( arg_t const* args ) const override
    	{
    		return m_obj( args[0], args[1] );
    	}
    };
    template< typename T >
    auto make_two_args( T&& obj )
    {
    	return std::move( std::make_unique< two_args_t< std::decay_t< T > > >( std::forward< T >( obj ) ) );
    }
    
    class callables_t
    {
    	std::map< std::size_t, std::unique_ptr< callable_t > > m_callables;
    
    public:
    	template< typename T, typename U >
    	void insert( T&& k, U&& v )
    	{
    		m_callables.insert( decltype( m_callables )::value_type{ std::forward< T >( k ), std::forward< U >( v ) } );
    	}
    
    	arg_t invoke( std::size_t n, arg_t const* args ) const
    	{
    		const auto finding = m_callables.find( n );
    		if( finding == m_callables.end() )
    		{
    			throw std::logic_error{ "invalid number of arguments" };
    		}
    		return finding->second->invoke( args );
    	}
    };
    
    int main()
    {
    	callables_t callables;
    	callables.insert( 1, make_one_arg( static_cast< arg_t( * )( arg_t )>( &std::sin ) ) );
    	callables.insert( 2, make_two_args( static_cast< arg_t( * )( arg_t, arg_t )>( &std::atan2 ) ) );
    	const std::array< arg_t, 2 > args{ 3.14159265 / 2, args[ 0 ] };
    	std::cout << callables.invoke( 1, args.data() ) << '\n';
    	std::cout << callables.invoke( 2, args.data() ) << '\n';
    }
    

    ich benutze hier one_arg_t und two_args_t um einen pointer auf argumente 'zu entpacken'. faellt euch eine moeglichkeit ein, wie ich das so abaendern kann, dass ich nur noch die anzahl an parametern als template-argument uebergeben kann, so dass danach der pointer automatisch 'extrahiert' wird, wie oben zu sehen in z.b. zeile 53?

    danke im voraus, lg


Anmelden zum Antworten