수색…


간단한 사용법

#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 :: bind와 함께 사용되는 std :: function

인수로 함수를 콜백해야하는 상황을 생각해보십시오. std::function std::bind 와 함께 사용되는 std::function 은 아래와 같이 매우 강력한 디자인 구조를 제공합니다.

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 with lambda와 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;
}

`함수`오버 헤드

std::function 은 상당한 오버 헤드를 유발할 수 있습니다. std::function 은 [value semantics] [1]을 가지고 있기 때문에 주어진 callable을 복사하거나 자신으로 옮겨야한다. 그러나 임의의 유형의 호출 가능 호출을 사용할 수 있으므로이 작업을 수행하기 위해 자주 동적으로 메모리를 할당해야합니다.

일부 function 구현은 소규모 유형 (함수 포인터, 멤버 포인터 또는 아주 작은 상태의 펑터)이 function 객체에 직접 저장되는 소위 "객체 최적화"를 가지고 있습니다. 그러나 이것은 심지어 유형이 noexcept move constructible 인 경우에만 작동합니다. 게다가, C ++ 표준은 모든 구현이 하나를 제공 할 것을 요구하지 않습니다.

다음을 고려하세요:

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

템플릿 매개 변수는 SortMyContainer 의 기본 솔루션 SortMyContainer , 어떤 이유로 든 가능하지 않거나 바람직하지 않다고 가정합니다. SortMyContainer 는 자신의 호출 이상으로 pred 를 저장할 필요가 없습니다. 그리고 pred 는 주어진 functor가 사소한 크기라면 메모리를 할당 할 수 있습니다.

function 는 복사 / 이동할 대상이 필요하기 때문에 메모리를 할당합니다. function 는 주어진 호출 가능 function 소유권을 가져옵니다. 그러나 SortMyContainer 는 호출 가능 SortMyContainer소유 할 필요가 없습니다. 그것은 단지 그것을 참조하고 있습니다. 그래서 여기에 function 사용 function 것은 잔인합니다. 그것은 효율적 일지 모르지만 그렇지 않을 수도 있습니다.

단순히 호출 가능을 참조하는 표준 라이브러리 함수 유형은 없습니다. 따라서 대체 솔루션을 찾아야하거나 오버 헤드로 살 수 있습니다.

또한, function 는 객체에 대한 메모리 할당이 어디에서 왔는지를 제어하는 ​​효과적인 수단이 없습니다. 예, allocator 사용하는 생성자가 있지만 [많은 구현에서는 올바르게 구현하지 못하거나 심지어 는 전혀 구현하지 않습니다] [2].

C ++ 17

allocator 취하는 function 생성자는 더 이상 유형의 일부가 아닙니다. 따라서 할당을 관리 할 방법이 없습니다.

function 호출하는 것은 내용을 직접 호출하는 것보다 느립니다. 어떤 때문에 function 인스턴스가 모든 호출을 잡을 수, 스루 호출 function 간접해야합니다. function 호출의 오버 헤드는 가상 함수 호출 순서입니다.

std :: function을 다른 호출 가능 유형에 바인딩

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

살고 있다

산출:

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

함수 인수를 std :: tuple에 저장

일부 프로그램은 향후 함수 호출을 위해 저장소 인수가 필요합니다.

이 예제는 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);
}

살고 있다

산출:

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


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow