c++ - objects - std::sort lambda




Wie konvertiert man ein Lambda zu einer std::-Funktion mit Vorlagen (4)

Dies könnte für Sie interessant sein: https://gist.github.com/Manu343726/94769034179e2c846acc

Das ist ein Experiment, das ich vor einem Monat geschrieben habe. Ziel war es, eine Funktor-ähnliche C ++ - Vorlage zu erstellen, die Haskells Partial Calls-Closures emuliert, dh die automatische Erstellung eines Abschlusses von Mn-Argumenten, wenn Sie mit einer m Parameter-Funktion eine Funktion aufrufen.

Dies ist ein Beispiel dafür, wofür dieses Experiment geeignet ist:

int f( int a, int b, int c, int d)
{
    return a+b+c+d;
}

int main()
{
    auto foo = haskell::make_function( f );

    auto a = foo , 1 , 2 , 3; //a is a closure function object with one parameter

    std::cout << a , 4 << std::endl; //Prints 10
}

haskell::make_function verwendet einige haskell::make_function , um auf die verschiedenen Typen von Funktionsentitäten, einschließlich haskell::make_function :

auto f = haskell::make_function( []( int x, int y , int z ){ return x*y*z; } );

auto a = f(1,2); //a is functor with one parameter (Using the alternative C++-like syntax)
auto b = a(3); // b is 6

Wie Sie sehen können, verwende ich den Komma-Operator, um die Haskell-Syntax zu mimikieren, aber Sie können ihn in den Aufrufoperator ändern, um Ihre Zielsyntax zu erreichen.

Sie sind völlig frei, mit dem Code alles zu tun, was Sie wollen (Überprüfen Sie die Lizenz).

Im Grunde genommen möchte ich ein Lambda mit einer beliebigen Anzahl von Parametern erzeugen und in eine std :: -Funktion umwandeln. Ich habe folgendes versucht und keine der Methoden funktioniert.

std::function([](){});//Complains that std::function is missing template parameters
template <typename T> void foo(function<T> f){}
foo([](){});//Complains that it cannot find a matching candidate

Der folgende Code funktioniert jedoch, aber es ist nicht das, was ich will, weil es erfordert, die Template-Parameter explizit anzugeben, die für generischen Code nicht funktioniert.

std::function<void()>([](){});

Ich habe den ganzen Abend mit Funktionen und Vorlagen herumgespielt und ich kann das einfach nicht herausfinden, also würde jede Hilfe sehr geschätzt werden.

Wie in einem Kommentar erwähnt, ist der Grund, warum ich versuche, dies zu tun, weil ich versuche, currying in C ++ mit variadischen Vorlagen zu implementieren. Leider scheitert das bei der Verwendung von Lambdas schrecklich. Zum Beispiel kann ich eine Standardfunktion mit einem Funktionszeiger übergeben.

template <typename R, typename...A>
void foo(R (*f)(A...)) {}
void bar() {}
int main() {
    foo(bar);
}

Ich kann jedoch nicht herausfinden, wie man ein Lambda an eine solche Varianzfunktion übergeben kann. Warum ich ein generisches Lambda in eine std :: -Funktion umwandeln möchte, liegt daran, dass ich Folgendes tun kann, aber letztendlich muss ich die Template-Parameter explizit auf std :: function angeben, was ich zu vermeiden versuche.

template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
    foo(std::function<void()>([](){}));
}

Es ist möglich, den benötigten std :: function type für Lambda mit Derivation, declype, variadic templates und einigen type traits zu erhalten:

namespace ambient {

    template <typename Function>
    struct function_traits : public function_traits<decltype(&Function::operator())> {};

    template <typename ClassType, typename ReturnType, typename... Args>
    struct function_traits<ReturnType(ClassType::*)(Args...) const> {
        typedef ReturnType (*pointer)(Args...);
        typedef const std::function<ReturnType(Args...)> function;
    };

    template <typename Function>
    typename function_traits<Function>::function to_function (Function& lambda) {
        return static_cast<typename function_traits<Function>::function>(lambda);
    }

    template <class L>
    struct overload_lambda : L {
        overload_lambda(L l) : L(l) {}
        template <typename... T>
        void operator()(T&& ... values){
            // here you can access the target std::function with
            to_function(*(L*)this)(std::forward<T>(values)...);
        }
    };

    template <class L>
    overload_lambda<L> lambda(L l){
        return overload_lambda<L>(l);
    }

}

Ich benutze es in meinem Code so:

ambient::lambda([&](const vector<int>& val){ // some code here // })(a);

PS: In meinem realen Fall speichere ich dann dieses std :: function-Objekt und seine Argumente in einem generischen Kernel-Objekt, das ich später bei Bedarf über virtuelle Funktionen ausführen kann.


Sie können ein lambda-Funktionsobjekt nicht als Argument vom Typ std::function<T> ohne das Template-Argument T explizit anzugeben. Der Template-Typ-Abzug versucht, den Typ Ihrer Lambda-Funktion mit der std::function<T> was in diesem Fall einfach nicht möglich ist - diese Typen sind nicht identisch. Die Template-Typ-Ableitung berücksichtigt keine Conversions zwischen Typen.

Es ist möglich, wenn Sie einen anderen Weg finden, den Typ abzuleiten. Sie können dies tun, indem Sie das Argument function in einen identity einfügen, so dass es nicht fehlschlägt, das lambda mit std::function (weil abhängige Typen werden einfach von der Typableitung ignoriert) und anderen Argumenten zu vergleichen.

template <typename T>
struct identity
{
  typedef T type;
};

template <typename... T>
void func(typename identity<std::function<void(T...)>>::type f, T... values) {
  f(values...);
}

int main() {
  func([](int x, int y, int z) { std::cout << (x*y*z) << std::endl; }, 3, 6, 8);
  return 0;
}

Dies ist jedoch in Ihrer Situation offensichtlich nicht sinnvoll, da Sie die Werte erst später weitergeben möchten.

Da Sie weder die Template-Parameter angeben noch andere Argumente übergeben möchten, aus denen die Template-Parameter abgeleitet werden können, kann der Compiler den Typ des Arguments std::function nicht ableiten.


Sie können eine dedizierte / retrospektive Besetzung verwenden . Sobald Sie ein Werkzeug wie dieses haben

#include <functional>

using namespace std;

template<typename T>
struct memfun_type
{
    using type = void;
};

template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
    using type = std::function<Ret(Args...)>;
};

template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
    return func;
}

Sie können allen Lambda-Typen FFL() sagen, damit sie in die korrekte Version von std::function konvertiert werden

template <typename... Args> void Callback(std::function<void(Args...)> f){
    // store f and call later
}

int main()
{
    Callback(FFL([](int a, float b){
        // do something
    }));

    return 0;
}

Display





lambda