Ist es möglich, den Parametertyp und den Rückgabetyp eines Lambda herauszufinden?

Lesezeit: 6 Minuten

Ist es moglich den Parametertyp und den Ruckgabetyp eines Lambda
Nawaz

Ist es bei einem Lambda möglich, dessen Parametertyp und Rückgabetyp herauszufinden? Wenn ja, wie?

Grundsätzlich möchte ich lambda_traits die auf folgende Weise verwendet werden können:

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

Die Motivation dahinter ist, dass ich sie nutzen möchte lambda_traits in einer Funktionsvorlage, die ein Lambda als Argument akzeptiert, und ich muss den Parametertyp und den Rückgabetyp innerhalb der Funktion kennen:

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!
   //...
}

Vorerst können wir davon ausgehen, dass das Lambda genau ein Argument akzeptiert.

Anfangs habe ich versucht, mit zu arbeiten std::function als:

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

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

Aber es würde offensichtlich Fehler geben. Also habe ich es geändert TLambda Version der Funktionsvorlage und wollen die konstruieren std::function Objekt innerhalb der Funktion (wie oben gezeigt).

  • Wenn Sie den Parametertyp kennen, kann dies verwendet werden, um den Rückgabetyp herauszufinden. Ich weiß jedoch nicht, wie ich den Parametertyp herausfinden soll.

    – Mankarse

    30. Oktober 2011 um 5:57 Uhr

  • Wird davon ausgegangen, dass die Funktion ein einzelnes Argument benötigt?

    – iammilind

    30. Oktober 2011 um 6:01 Uhr

  • “Parametertyp” Aber eine beliebige Lambda-Funktion hat keinen Parametertyp. Es könnte eine beliebige Anzahl von Parametern annehmen. Daher müsste jede Merkmalsklasse so konzipiert sein, dass sie Parameter nach Positionsindizes abfragt.

    – Nicol Bolas

    30. Oktober 2011 um 6:01 Uhr

  • @iammilind: Ja. davon können wir vorerst ausgehen.

    – Nawaz

    30. Oktober 2011 um 6:03 Uhr

  • @NicolBolas: Derzeit können wir davon ausgehen, dass das Lambda genau ein Argument akzeptiert.

    – Nawaz

    30. Oktober 2011 um 6:03 Uhr

Ist es moglich den Parametertyp und den Ruckgabetyp eines Lambda
kennytm

Komisch, ich habe gerade einen geschrieben function_traits Implementierung beyogen auf Spezialisieren eines Templates auf ein Lambda in C++0x die die Parametertypen geben können. Der Trick, wie in der Antwort auf diese Frage beschrieben, besteht darin, die zu verwenden decltype der Lambdas 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;
}

Beachten Sie, dass diese Lösung nicht Arbeit für generisches Lambda wie [](auto x) {}.

  • Heh, das habe ich gerade geschrieben. Nicht darüber nachgedacht tuple_element trotzdem danke.

    – GManNickG

    30. Oktober 2011 um 7:30 Uhr

  • @GMan: Wenn Ihr Ansatz nicht genau so ist, posten Sie ihn bitte. Ich werde diese Lösung testen.

    – Nawaz

    30. Oktober 2011 um 7:33 Uhr


  • Eine vollständige Eigenschaft würde auch eine Spezialisierung für nicht-constfür die deklarierten Lambda mutable ([]() mutable -> T { ... }).

    – Luc Danton

    30. Oktober 2011 um 10:14 Uhr

  • @Andry das ist ein grundlegendes Problem mit Funktionsobjekten, die (möglicherweise) mehrere Überladungen von haben operator() nicht mit dieser Implementierung. auto ist kein Typ, also kann es niemals die Antwort auf sein traits::template arg<0>::type

    – Caleth

    16. Januar 2018 um 12:19 Uhr

  • @helmesjo sf.net/p/tacklelib/tacklelib/HEAD/tree/trunk/include/tacklelib/… Als Lösung für defekte Links: Versuchen Sie, von der Wurzel aus zu suchen, Luke.

    – Andry

    17. Januar 2019 um 7:59 Uhr


Obwohl ich nicht sicher bin, ob dies streng standardkonform ist,
Idee folgenden Code kompiliert:

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, "" );
}

Diese liefert jedoch nur den Funktionstyp, sodass Ergebnis- und Parametertypen daraus extrahiert werden müssen. Wenn Sie verwenden können boost::function_traits, result_type und arg1_type
wird den Zweck erfüllen. Da ideone im C++11-Modus anscheinend keinen Boost bietet, konnte ich den eigentlichen Code leider nicht posten.

  • Ich denke, es ist ein guter Anfang. +1 dafür. Jetzt müssen wir am Funktionstyp arbeiten, um die erforderlichen Informationen zu extrahieren. (Ich möchte Boost jetzt nicht verwenden, da ich es möchte lernen die Stoffe).

    – Nawaz

    30. Oktober 2011 um 7:22 Uhr


1647171610 966 Ist es moglich den Parametertyp und den Ruckgabetyp eines Lambda
Columbo

Die in @KennyTMs Antwort gezeigte Spezialisierungsmethode kann erweitert werden, um alle Fälle abzudecken, einschließlich variadischer und veränderlicher Lambdas:

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.

Beachten Sie, dass die Arität nicht für Variadic angepasst wird operator()S. Stattdessen kann man auch überlegen is_variadic.

Die Antwort von @KennyTMs funktioniert hervorragend, aber wenn ein Lambda keine Parameter hat, wird die Verwendung des Index arg<0> nicht kompiliert. Wenn jemand anderes dieses Problem hatte, habe ich eine einfache Lösung (einfacher als die Verwendung von SFINAE-bezogenen Lösungen).

Fügen Sie einfach void am Ende des Tupels in der arg-Struktur nach den variadischen Argumenttypen hinzu. dh

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

Da die arität nicht von der tatsächlichen Anzahl der Vorlagenparameter abhängt, ist die tatsächliche nicht falsch, und wenn sie 0 ist, wird zumindest arg<0> noch vorhanden sein, und Sie können damit machen, was Sie wollen. Wenn Sie bereits planen, den Index nicht zu überschreiten arg<arity-1> dann sollte es Ihre aktuelle Implementierung nicht stören.

997430cookie-checkIst es möglich, den Parametertyp und den Rückgabetyp eines Lambda herauszufinden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy