È possibile capire il tipo di parametro e di tipo di ritorno di una lambda?

Dato un lambda, è possibile capire è il tipo di parametro e di tipo di ritorno? Se sì, come?

Fondamentalmente, io voglio lambda_traits che può essere utilizzato nei seguenti modi:

auto lambda = [](int i) { return long(i*10); };

lambda_traits<decltype(lambda)>::param_type  i; //i should be int
lambda_traits<decltype(lambda)>::return_type l; //l should be long

La motivazione di fondo è che voglio usare lambda_traits in un modello di funzione che accetta un lambda come argomento, e ho bisogno di sapere è il tipo di parametro e di tipo di ritorno all’interno della funzione:

template<typename TLambda>
void f(TLambda lambda)
{
   typedef typename lambda_traits<TLambda>::param_type  P;
   typedef typename lambda_traits<TLambda>::return_type R;

   std::function<R(P)> fun = lambda; //I want to do this!
   //...
}

Per il momento, si può supporre che la lambda prende esattamente un argomento.

Inizialmente, ho provato a lavorare con std::function come:

template<typename T>
A<T> f(std::function<bool(T)> fun)
{
   return A<T>(fun);
}

f([](int){return true;}); //error

Ma ovviamente darebbe errore. Così ho cambiato TLambda versione del template di funzione e si desidera costruire la std::function oggetto all’interno della funzione (come mostrato sopra).

Se conosci il tipo del parametro, quindi this può essere usato per capire il tipo di ritorno. Non so come capire il tipo di parametro.
Si ipotizza che la funzione accetta un solo argomento ?
parametro “tipo”, Ma un’arbitraria funzione lambda non ha un parametro di tipo. Si potrebbe prendere un qualsiasi numero di parametri. Quindi, qualsiasi classe di tratti dovrebbe essere progettato per parametri di query di posizione indici.
Sì. per il momento, si può supporre che.
Per il momento, si può supporre che la lambda prende esattamente un argomento.

OriginaleL’autore Nawaz | 2011-10-30

4 Replies
  1. 149

    Divertente, ho appena scritto un function_traits attuazione basato sul Specializzato di un modello su un lambda in C++0x che può dare i tipi di parametro. Il trucco, come descritto nella risposta a questa domanda, è quello di utilizzare il decltype della lambda operator().

    template <typename T>
    struct function_traits
        : public function_traits<decltype(&T::operator())>
    {};
    //For generic types, directly use the result of the signature of its 'operator()'
    
    template <typename ClassType, typename ReturnType, typename... Args>
    struct function_traits<ReturnType(ClassType::*)(Args...) const>
    //we specialize for pointers to member function
    {
        enum { arity = sizeof...(Args) };
        //arity is the number of arguments.
    
        typedef ReturnType result_type;
    
        template <size_t i>
        struct arg
        {
            typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
            //the i-th argument is equivalent to the i-th tuple element of a tuple
            //composed of those arguments.
        };
    };
    
    //test code below:
    int main()
    {
        auto lambda = [](int i) { return long(i*10); };
    
        typedef function_traits<decltype(lambda)> traits;
    
        static_assert(std::is_same<long, traits::result_type>::value, "err");
        static_assert(std::is_same<int, traits::arg<0>::type>::value, "err");
    
        return 0;
    }

    Di notare che questa soluzione non di lavoro per generico lambda come [](auto x) {}.

    Eh, stavo solo scrivendo questo. Non pensare di tuple_element però, grazie.
    Se il tuo approccio non è esattamente lo stesso come questo, si prega di inviare poi. Ho intenzione di testare questa soluzione.
    L’utilità di Kenny collegato è quasi identica alla mia utilità che ho per i miei progetti. (Devo solo Aumentare.PP scorrere dal momento che mi sono bloccato in MSVC C++0x supporto.) L’unica cosa è che ho scritto un get_nth_element meta-funzione, invece di (ab)uso di tuple_element.
    Un completo tratto sarebbe anche utilizzare una specializzazione per i non-const, per chi lambda dichiarato mutable ([]() mutable -> T { ... }).
    questo è un problema fondamentale con la funzione di oggetti che sono (potenzialmente) più sovraccarichi di operator() non con questa implementazione. auto non è un tipo, in modo che non può mai essere la risposta a traits::template arg<0>::type

    OriginaleL’autore kennytm

  2. 11

    Anche se non sono sicuro che questo è strettamente conforme agli standard,
    ideone compilato il seguente codice:

    template< class > struct mem_type;
    
    template< class C, class T > struct mem_type< T C::* > {
      typedef T type;
    };
    
    template< class T > struct lambda_func_type {
      typedef typename mem_type< decltype( &T::operator() ) >::type type;
    };
    
    int main() {
      auto l = [](int i) { return long(i); };
      typedef lambda_func_type< decltype(l) >::type T;
      static_assert( std::is_same< T, long( int )const >::value, "" );
    }

    Tuttavia, questo fornisce solo il tipo di funzione, in modo che il risultato e il parametro
    tipi devono essere estratti.
    Se è possibile utilizzare boost::function_traits, result_type e arg1_type
    si incontreranno allo scopo.
    Dal momento che ideone sembra di non fornire la spinta in C++11 modalità, non riuscivo a postare
    il codice vero e proprio, mi dispiace.

    Io penso che è un buon inizio. +1 per questo. Ora abbiamo bisogno di lavorare sul tipo di funzione per estrarre le informazioni richieste. (Non voglio usare Boost ora come ora, voglio imparare stoffe).

    OriginaleL’autore Ise Wisteria

  3. 6

    Specializzazione metodo illustrato in @KennyTMs risposta può essere esteso per coprire tutti i casi, compresi variadic e mutevole lambda:

    template <typename T>
    struct closure_traits : closure_traits<decltype(&T::operator())> {};
    
    #define REM_CTOR(...) __VA_ARGS__
    #define SPEC(cv, var, is_var)                                              \
    template <typename C, typename R, typename... Args>                        \
    struct closure_traits<R (C::*) (Args... REM_CTOR var) cv>                  \
    {                                                                          \
        using arity = std::integral_constant<std::size_t, sizeof...(Args) >;   \
        using is_variadic = std::integral_constant<bool, is_var>;              \
        using is_const    = std::is_const<int cv>;                             \
                                                                               \
        using result_type = R;                                                 \
                                                                               \
        template <std::size_t i>                                               \
        using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; \
    };
    
    SPEC(const, (,...), 1)
    SPEC(const, (), 0)
    SPEC(, (,...), 1)
    SPEC(, (), 0)

    Demo.

    Di notare che la sioni non è regolato per variadic operator()s. Invece si può anche considerare di is_variadic.

    OriginaleL’autore Columbo

  4. 1

    La risposta fornita da @KennyTMs funziona alla grande, però se un lambda non ha parametri, utilizzando l’indice arg<0> non compilare. Se qualcun altro stava avendo questo problema, ho una soluzione semplice (più semplice rispetto all’utilizzo SFINAE relative soluzioni, che è).

    Basta aggiungere vuoto alla fine di una tupla in arg struct dopo il variadic tipi di argomento. cioè

    template <size_t i>
        struct arg
        {
            typedef typename std::tuple_element<i, std::tuple<Args...,void>>::type type;
        };

    dal sioni e non dipende dall’effettivo numero di parametri del modello, l’attuale non essere corretto, e se è 0 allora almeno arg<0> ancora esiste e si può fare con quello che volete. Se avete già in programma di non superi l’indice arg<arity-1> quindi non dovrebbe interferire con l’attuale implementazione.

    OriginaleL’autore Jon Koelzer

Lascia un commento