Suche…


Einfache Benutzung

#include <iostream>
#include <functional>
std::function<void(int , const std::string&)> myFuncObj;
void theFunc(int i, const std::string& s)
{
    std::cout << s << ": " << i << std::endl;
}
int main(int argc, char *argv[])
{
    myFuncObj = theFunc;
    myFuncObj(10, "hello world");
}

std :: function wird mit std :: bind verwendet

Denken Sie an eine Situation, in der wir eine Funktion mit Argumenten zurückrufen müssen. std::function mit std::bind verwendete std::function std::bind ergibt ein sehr leistungsfähiges Konstrukt wie unten gezeigt.

class A
{
public:
    std::function<void(int, const std::string&)> m_CbFunc = nullptr;
    void foo()
    {
        if (m_CbFunc)
        {
            m_CbFunc(100, "event fired");
        }
    }

};

class B
{
public:
    B()
    {
        auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2);
        anObjA.m_CbFunc = aFunc;
    }
    void eventHandler(int i, const std::string& s)
    {
        std::cout << s << ": " << i << std::endl;
    }

    void DoSomethingOnA()
    {
        anObjA.foo();
    }

    A anObjA;
};

int main(int argc, char *argv[])
{
     B anObjB;
     anObjB.DoSomethingOnA();
}

std :: function mit Lambda und std :: bind

#include <iostream>
#include <functional>

using std::placeholders::_1; // to be used in std::bind example

int stdf_foobar (int x, std::function<int(int)> moo)
{
    return x + moo(x); // std::function moo called
}

int foo (int x) { return 2+x; }

int foo_2 (int x, int y) { return 9*x + y; }

int main()
{
    int a = 2;

    /* Function pointers */
    std::cout << stdf_foobar(a, &foo) << std::endl; // 6 ( 2 + (2+2) )
    // can also be: stdf_foobar(2, foo)

    /* Lambda expressions */
    /* An unnamed closure from a lambda expression can be
     * stored in a std::function object:
     */
    int capture_value = 3;
    std::cout << stdf_foobar(a,
                             [capture_value](int param) -> int { return 7 + capture_value * param; })
              << std::endl;
    // result: 15 ==  value + (7 * capture_value * value) == 2 + (7 + 3 * 2)

    /* std::bind expressions */
    /* The result of a std::bind expression can be passed.
     * For example by binding parameters to a function pointer call:
     */    
    int b = stdf_foobar(a, std::bind(foo_2, _1, 3));
    std::cout << b << std::endl;
    // b == 23 == 2 + ( 9*2 + 3 )
    int c = stdf_foobar(a, std::bind(foo_2, 5, _1));
    std::cout << c << std::endl;
    // c == 49 == 2 + ( 9*5 + 2 )

    return 0;
}

`function` overhead

std::function kann erheblichen Overhead verursachen. Da std::function [Wertsemantik] [1] hat, muss sie die angegebene aufrufbare Funktion in sich selbst kopieren oder verschieben. Da jedoch Callables eines beliebigen Typs verwendet werden können, muss häufig Speicher dynamisch zugewiesen werden, um dies auszuführen.

Einige function verfügen über eine sogenannte "Small-Object-Optimization", bei der kleine Typen (wie Funktionszeiger, Member-Zeiger oder Funktionen mit sehr wenig Status) direkt im function gespeichert werden. Aber auch das funktioniert nur, wenn der Typ noexcept Move ist. Darüber hinaus erfordert der C ++ - Standard nicht, dass alle Implementierungen eine bereitstellen.

Folgendes berücksichtigen:

//Header file
using MyPredicate = std::function<bool(const MyValue &, const MyValue &)>;

void SortMyContainer(MyContainer &C, const MyPredicate &pred);

//Source file
void SortMyContainer(MyContainer &C, const MyPredicate &pred)
{
    std::sort(C.begin(), C.end(), pred);
}

Ein Vorlagenparameter wäre die bevorzugte Lösung für SortMyContainer , aber nehmen wir an, dass dies aus irgendeinem Grund nicht möglich oder wünschenswert ist. SortMyContainer muss pred hinter seinem eigenen Aufruf nicht speichern. pred kann jedoch durchaus Speicher zuweisen, wenn der ihm zugewiesene Funktionsumfang nicht trivial ist.

function weist Speicher zu, da etwas zum Kopieren / Verschieben benötigt wird; function übernimmt den Besitz des Aufrufbaren. SortMyContainer muss jedoch nicht das SortMyContainer besitzen . es bezieht sich nur darauf. Die function hier ist also ein Overkill; Es kann effizient sein, aber nicht.

Es gibt keinen Standardfunktionstyp für Bibliotheken, der nur auf eine aufrufbare Funktion verweist. Es muss also eine alternative Lösung gefunden werden, oder Sie können wählen, ob Sie mit dem Overhead leben möchten.

Die function hat auch keine wirksamen Mittel, um zu steuern, woher die Speicherzuordnungen für das Objekt stammen. Ja, es gibt Konstruktoren, die einen allocator benötigen, aber [viele Implementierungen implementieren sie nicht korrekt ... oder sogar überhaupt ] [2].

C ++ 17

Die function , die einen allocator nicht mehr Teil des Typs. Daher gibt es keine Möglichkeit, die Zuordnung zu verwalten.

Das Aufrufen einer function ist auch langsamer als das direkte Aufrufen des Inhalts. Da jede function aufrufbare Objekte enthalten kann, muss der Aufruf über eine function indirekt sein. Der Aufwand der aufrufenden function liegt in der Reihenfolge eines virtuellen Funktionsaufrufs.

Bindet std :: function an andere aufrufbare Typen

/*
 * This example show some ways of using std::function to call
 *  a) C-like function
 *  b) class-member function
 *  c) operator()
 *  d) lambda function
 *
 * Function call can be made:
 *  a) with right arguments
 *  b) argumens with different order, types and count
 */
#include <iostream>
#include <functional>
#include <iostream>
#include <vector>

using std::cout;
using std::endl;
using namespace std::placeholders;



// simple function to be called
double foo_fn(int x, float y, double z)
{
  double res = x + y + z;
  std::cout << "foo_fn called with arguments: " 
            << x << ", " << y << ", " << z 
            << " result is : " << res 
            << std::endl;
  return res;
}

// structure with member function to call
struct foo_struct
{
    // member function to call
    double foo_fn(int x, float y, double z)
    {
        double res = x + y + z;
        std::cout << "foo_struct::foo_fn called with arguments: " 
                << x << ", " << y << ", " << z 
                << " result is : " << res 
                << std::endl;
        return res;
    }
    // this member function has different signature - but it can be used too
    // please not that argument order is changed too
    double foo_fn_4(int x, double z, float y, long xx)
    {
        double res = x + y + z + xx;
        std::cout << "foo_struct::foo_fn_4 called with arguments: " 
                << x << ", " << z << ", " << y << ", " << xx
                << " result is : " << res 
                << std::endl;
        return res;
    }
    // overloaded operator() makes whole object to be callable
    double operator()(int x, float y, double z)
    {
        double res = x + y + z;
        std::cout << "foo_struct::operator() called with arguments: " 
                << x << ", " << y << ", " << z 
                << " result is : " << res 
                << std::endl;
        return res;
    }
};


int main(void)
{
  // typedefs
  using function_type = std::function<double(int, float, double)>;

  // foo_struct instance
  foo_struct fs;
  
  // here we will store all binded functions 
  std::vector<function_type> bindings;

  // var #1 - you can use simple function
  function_type var1 = foo_fn;
  bindings.push_back(var1);
  
  // var #2 - you can use member function 
  function_type var2 = std::bind(&foo_struct::foo_fn, fs, _1, _2, _3);
  bindings.push_back(var2);
  
  // var #3 - you can use member function with different signature
  // foo_fn_4 has different count of arguments and types
  function_type var3 = std::bind(&foo_struct::foo_fn_4, fs, _1, _3, _2, 0l);
  bindings.push_back(var3);

  // var #4 - you can use object with overloaded operator() 
  function_type var4 = fs;
  bindings.push_back(var4);

  // var #5 - you can use lambda function
  function_type var5 = [](int x, float y, double z)
    {
        double res = x + y + z;
        std::cout << "lambda  called with arguments: " 
                << x << ", " << y << ", " << z 
                << " result is : " << res 
                << std::endl;
        return res;
    };
  bindings.push_back(var5);
    
  std::cout << "Test stored functions with arguments: x = 1, y = 2, z = 3" 
            << std::endl;
  
  for (auto f : bindings)
      f(1, 2, 3);
      
}

Leben

Ausgabe:

Test stored functions with arguments: x = 1, y = 2, z = 3
foo_fn called with arguments: 1, 2, 3 result is : 6
foo_struct::foo_fn called with arguments: 1, 2, 3 result is : 6
foo_struct::foo_fn_4 called with arguments: 1, 3, 2, 0 result is : 6
foo_struct::operator() called with arguments: 1, 2, 3 result is : 6
lambda  called with arguments: 1, 2, 3 result is : 6

Speichern von Funktionsargumenten in std :: tuple

Einige Programme müssen daher Argumente für den späteren Aufruf einer Funktion speichern.

In diesem Beispiel wird gezeigt, wie eine Funktion mit in std :: tuple gespeicherten Argumenten aufgerufen wird

#include <iostream>
#include <functional>
#include <tuple>
#include <iostream>

// simple function to be called
double foo_fn(int x, float y, double z)
{
   double res =  x + y + z;
   std::cout << "foo_fn called. x = " << x << " y = " << y << " z = " << z
             << " res=" << res;
   return res;
}

// helpers for tuple unrolling
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };

// invocation helper 
template<typename FN, typename P, int ...S>
double call_fn_internal(const FN& fn, const P& params, const seq<S...>)
{
   return fn(std::get<S>(params) ...);
}
// call function with arguments stored in std::tuple
template<typename Ret, typename ...Args>
Ret call_fn(const std::function<Ret(Args...)>& fn, 
            const std::tuple<Args...>& params)
{
    return call_fn_internal(fn, params, typename gens<sizeof...(Args)>::type());
}


int main(void)
{
  // arguments
  std::tuple<int, float, double> t = std::make_tuple(1, 5, 10);
  // function to call
  std::function<double(int, float, double)> fn = foo_fn;
  
  // invoke a function with stored arguments
  call_fn(fn, t);
}

Leben

Ausgabe:

foo_fn called. x = 1 y = 5 z = 10 res=16


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow