Sök…


Enkel användning

#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 :: funktion som används med std :: bind

Tänk på en situation där vi måste återkalla en funktion med argument. std::function används med std::bind ger en mycket kraftfull designkonstruktion som visas nedan.

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 :: funktion med lambda och 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;
}

"funktion" overhead

std::function kan orsaka betydande omkostnader. Eftersom std::function har [värde semantik] [1], måste den kopiera eller flytta den givna konverterbara till sig själv. Men eftersom det kan ta avräkningar av godtycklig typ måste det ofta tilldelas minne dynamiskt för att göra detta.

Vissa function har så kallade "small object optimization", där små typer (som funktionspekare, medlemspekare eller funktorer med mycket lite tillstånd) kommer att lagras direkt i function . Men även detta fungerar bara om typen är noexcept . Dessutom kräver C ++ -standarden inte att alla implementationer tillhandahåller en.

Tänk på följande:

//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);
}

En mallparameter skulle vara den föredragna lösningen för SortMyContainer , men låt oss anta att detta inte är möjligt eller önskvärt av någon anledning. SortMyContainer behöver inte lagra pred utöver sitt eget samtal. Och ändå kan pred mycket väl tilldela minne om funktorn som ges till den är av någon icke-trivial storlek.

function allokerar minne eftersom den behöver något att kopiera / flytta till; function tar äganderätt till den kvittningsbara den ges. Men SortMyContainer behöver inte äga det avräknbara; det hänvisar bara till det. Så att använda function här är överdöd; det kan vara effektivt, men det kanske inte.

Det finns ingen standardbiblioteksfunktionstyp som bara hänvisar till en konverterbar. Så en alternativ lösning måste hittas, eller så kan du välja att leva med overhead.

function har inte heller några effektiva sätt att kontrollera var minnesallokeringarna för objektet kommer från. Ja, det har konstruktörer som tar en allocator , men [många implementationer implementerar dem inte korrekt ... eller ens alls ] [2].

C ++ 17

function som tar en allocator inte längre en del av typen. Därför finns det inget sätt att hantera allokeringen.

Att ringa en function är också långsammare än att ringa innehållet direkt. Eftersom alla function kan innehålla valbara, måste samtalet via en function vara indirekt. Overhead att ringa function är i storleksordningen av en virtuell samtalsfunktion.

Bindande std :: funktion till olika typer som kan kallas in

/*
 * 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);
      
}

leva

Produktion:

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

Lagra funktionsargument i std :: tuple

Vissa program behöver så lagra argument för framtida samtal av någon funktion.

Det här exemplet visar hur man ringer till någon funktion med argument lagrade i std :: tuple

#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);
}

leva

Produktion:

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


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow