web-dev-qa-db-ja.com

C++のファンクタとその用途は何ですか?

私はC++の関数について多くのことを聞いています。誰かが彼らが何であるか、そしてどのような場合にそれらが有用であろうかについての概要を私に教えてもらえますか?

787
Konrad

ファンクタは、単なるoperator()を定義するクラスです。これにより、関数のように見えるオブジェクトを作成できます。

// this is a functor
struct add_x {
  add_x(int x) : x(x) {}
  int operator()(int y) const { return x + y; }

private:
  int x;
};

// Now you can use it like this:
add_x add42(42); // create an instance of the functor class
int i = add42(8); // and "call" it
assert(i == 50); // and it added 42 to its argument

std::vector<int> in; // assume this contains a bunch of values)
std::vector<int> out(in.size());
// Pass a functor to std::transform, which calls the functor on every element 
// in the input sequence, and stores the result to the output sequence
std::transform(in.begin(), in.end(), out.begin(), add_x(1)); 
assert(out[i] == in[i] + 1); // for all i

ファンクターについていくつかいいことがあります。 1つは、通常の関数とは異なり、状態を含めることができるということです。上記の例では、あなたが与えたものに42を加える関数を作成しています。しかし、その値42はハードコーディングされておらず、ファンクタインスタンスを作成したときにコンストラクタ引数として指定されていました。私は別の加算器を作成することができました、それは27を追加しました、ちょうど異なる値でコンストラクタを呼び出すことによって。これはそれらをうまくカスタマイズ可能にします。

最後の行が示すように、多くの場合、std :: transformや他の標準ライブラリアルゴリズムなどの他の関数への引数として関数子を渡します。通常の関数ポインタでも同じことができますが、前述したように、ファンクタには状態が含まれているため柔軟であるため「カスタマイズ」することができます(関数ポインタを使用する場合は関数を作成する必要があります)。ファンクタは一般的なもので、初期化したものをすべて追加したもので、潜在的により効率的です。上記の例では、コンパイラはどの関数std::transformを呼び出すべきかを正確に知っています。 add_x::operator()を呼び出す必要があります。つまり、その関数呼び出しをインライン化できるということです。そしてそれは私がベクトルの各値で手動で関数を呼び出したのと同じくらい効率的になります。

代わりに関数ポインタを渡した場合、コンパイラはそれが指す関数をすぐには知ることができませんでした。したがって、かなり複雑なグローバル最適化を実行しない限り、実行時にポインタを間接参照してから呼び出しを行う必要があります。

949
jalf

少し足し算。 boost::function を使用すると、関数やメソッドからファンクタを作成できます。

class Foo
{
public:
    void operator () (int i) { printf("Foo %d", i); }
};
void Bar(int i) { printf("Bar %d", i); }
Foo foo;
boost::function<void (int)> f(foo);//wrap functor
f(1);//prints "Foo 1"
boost::function<void (int)> b(&Bar);//wrap normal function
b(1);//prints "Bar 1"

そして、このファンクタに状態を追加するためにboost :: bindを使うことができます。

boost::function<void ()> f1 = boost::bind(foo, 2);
f1();//no more argument, function argument stored in f1
//and this print "Foo 2" (:
//and normal function
boost::function<void ()> b1 = boost::bind(&Bar, 2);
b1();// print "Bar 2"

そして最も便利な、boost :: bindとboost :: functionを使えば、クラスメソッドからファンクタを作成することができる。実際にはこれはデリゲートである:

class SomeClass
{
    std::string state_;
public:
    SomeClass(const char* s) : state_(s) {}

    void method( std::string param )
    {
        std::cout << state_ << param << std::endl;
    }
};
SomeClass *inst = new SomeClass("Hi, i am ");
boost::function< void (std::string) > callback;
callback = boost::bind(&SomeClass::method, inst, _1);//create delegate
//_1 is a placeholder it holds plase for parameter
callback("useless");//prints "Hi, i am useless"

ファンクタのリストまたはベクトルを作成できます

std::list< boost::function<void (EventArg e)> > events;
//add some events
....
//call them
std::for_each(
        events.begin(), events.end(), 
        boost::bind( boost::apply<void>(), _1, e));

これらすべてには1つ問題があります、コンパイラのエラーメッセージは人間が読むことができません:)

117
Lazin

Functorは関数のように振る舞うオブジェクトです。基本的にはoperator()を定義するクラスです。

class MyFunctor
{
   public:
     int operator()(int x) { return x * 2;}
}

MyFunctor doubler;
int x = doubler(5);

真の利点は、ファンクタが状態を保持できることです。

class Matcher
{
   int target;
   public:
     Matcher(int m) : target(m) {}
     bool operator()(int x) { return x == target;}
}

Matcher Is5(5);

if (Is5(n))    // same as if (n == 5)
{ ....}
87
James Curran

C++が登場するずっと以前から、「ファンクター」という名前が カテゴリ理論 で使われてきました。これは、C++のFunctorの概念とは関係ありません。 C++で "functor"と呼ぶものの代わりに、name function object を使うのが良いでしょう。これが他のプログラミング言語が同様の構成要素を呼び出す方法です。

普通の関数の代わりに使われる:

特徴:

  • 関数オブジェクトは状態を持つことができます
  • 関数オブジェクトはOOPに収まります(他のすべてのオブジェクトと同じように動作します)。

短所:

  • プログラムをより複雑にします。

関数ポインタの代わりに使用されます。

特徴:

  • 関数オブジェクトはインライン展開されることが多い

短所:

  • 実行時には、関数オブジェクトを他の関数オブジェクト型と交換することはできません(少なくとも何らかの基本クラスを拡張しない限りオーバーヘッドが発生します)。

仮想関数の代わりに使用されます。

特徴:

  • 関数オブジェクト(非仮想)はvtableやランタイムのディスパッチを必要としないので、ほとんどの場合より効率的です。

短所:

  • 実行時には、関数オブジェクトを他の関数オブジェクト型と交換することはできません(少なくとも何らかの基本クラスを拡張しない限りオーバーヘッドが発生します)。
45
doc

他の人が述べたように、ファンクターは関数のように振る舞うオブジェクトです。すなわち、それは関数呼び出し演算子をオーバーロードします。

ファンクタは、STLアルゴリズムで一般的に使用されています。関数型言語のクロージャのように、関数呼び出しの前後に状態を保持できるため、これらは便利です。たとえば、引数に指定量を乗算するMultiplyByファンクタを定義できます。

class MultiplyBy {
private:
    int factor;

public:
    MultiplyBy(int x) : factor(x) {
    }

    int operator () (int other) const {
        return factor * other;
    }
};

それからMultiplyByオブジェクトをstd :: transformのようなアルゴリズムに渡すことができます。

int array[5] = {1, 2, 3, 4, 5};
std::transform(array, array + 5, array, MultiplyBy(3));
// Now, array is {3, 6, 9, 12, 15}

関数へのポインタに対するファンクタのもう1つの利点は、呼び出しがより多くの場合インライン化できることです。関数ポインタをtransformに渡した場合、 that callがインライン化され、コンパイラが常に同じ関数を渡すことを認識していない限り、ポインタを介して呼び出しをインライン化することはできません。

36
Matthew Crumley

私たちのような初心者のために:ちょっとした調査の後、私はjalfが投稿したコードが何をするのかを考え出しました。

ファンクターは、関数のように「呼び出す」ことができるクラスまたは構造体オブジェクトです。これは() operatorをオーバーロードすることによって可能になります。 () operator(呼び出されたものがわからない)は任意の数の引数を取ることができます。他の演算子は2つのみを取ります。つまり、+ operatorは2つの値(演算子の両側に1つずつ)を取り、オーバーロードした値はすべて返します。 () operatorの中にいくつでも引数を入れることができ、それが柔軟性をもたらします。

ファンクターを作成するには、まずクラスを作成します。次に、選択した型と名前のパラメータを使用してクラスにコンストラクタを作成します。これと同じステートメントの後に、コンストラクターに対して以前に宣言されたパラメーターを使用してクラス・メンバー・オブジェクトを構成するイニシャライザー・リスト(単一のコロン演算子を使用します。これも私は初めてでした)が続きます。それから() operatorはオーバーロードされます。最後に、作成したクラスまたは構造体のプライベートオブジェクトを宣言します。

私のコード(私はjalfの変数名が分かりにくいと思いました)

class myFunctor
{ 
    public:
        /* myFunctor is the constructor. parameterVar is the parameter passed to
           the constructor. : is the initializer list operator. myObject is the
           private member object of the myFunctor class. parameterVar is passed
           to the () operator which takes it and adds it to myObject in the
           overloaded () operator function. */
        myFunctor (int parameterVar) : myObject( parameterVar ) {}

        /* the "operator" Word is a keyword which indicates this function is an 
           overloaded operator function. The () following this just tells the
           compiler that () is the operator being overloaded. Following that is
           the parameter for the overloaded operator. This parameter is actually
           the argument "parameterVar" passed by the constructor we just wrote.
           The last part of this statement is the overloaded operators body
           which adds the parameter passed to the member object. */
        int operator() (int myArgument) { return myObject + myArgument; }

    private: 
        int myObject; //Our private member object.
}; 

これのどれかが不正確であるか、または単に明白に間違っているならば、私を直して自由に感じてください!

34
Johanne Irish

ファンクターは、 高階関数 で、パラメータ化された(すなわちテンプレート化された)型に関数を適用します。 map 高階関数を一般化したものです。たとえば、std::vectorのファンクターを次のように定義できます。

template<class F, class T, class U=decltype(std::declval<F>()(std::declval<T>()))>
std::vector<U> fmap(F f, const std::vector<T>& vec)
{
    std::vector<U> result;
    std::transform(vec.begin(), vec.end(), std::back_inserter(result), f);
    return result;
}

Fを取り、Tを返す関数Uが与えられたとき、この関数はstd::vector<T>を取り、std::vector<U>を戻します。ファンクタはコンテナ型に対して定義する必要はなく、std::shared_ptrを含む任意のテンプレート型に対しても定義できます。

template<class F, class T, class U=decltype(std::declval<F>()(std::declval<T>()))>
std::shared_ptr<U> fmap(F f, const std::shared_ptr<T>& p)
{
    if (p == nullptr) return nullptr;
    else return std::shared_ptr<U>(new U(f(*p)));
}

型をdoubleに変換する簡単な例があります。

double to_double(int x)
{
    return x;
}

std::shared_ptr<int> i(new int(3));
std::shared_ptr<double> d = fmap(to_double, i);

std::vector<int> is = { 1, 2, 3 };
std::vector<double> ds = fmap(to_double, is);

ファンクタが従うべき2つの法則があります。 1つ目は恒等法です。ファンクタに恒等関数が与えられると、恒等式を型に適用するのと同じになるはずです。つまりfmap(identity, x)identity(x)と同じになるはずです。

struct identity_f
{
    template<class T>
    T operator()(T x) const
    {
        return x;
    }
};
identity_f identity = {};

std::vector<int> is = { 1, 2, 3 };
// These two statements should be equivalent.
// is1 should equal is2
std::vector<int> is1 = fmap(identity, is);
std::vector<int> is2 = identity(is);

次の法則は合成法です。つまり、関数に2つの関数の組み合わせが与えられた場合、最初の関数に関数を適用し、次に2番目の関数に関数を適用するのと同じになります。したがって、fmap(std::bind(f, std::bind(g, _1)), x)fmap(f, fmap(g, x))と同じである必要があります。

double to_double(int x)
{
    return x;
}

struct foo
{
    double x;
};

foo to_foo(double x)
{
    foo r;
    r.x = x;
    return r;
}

std::vector<int> is = { 1, 2, 3 };
// These two statements should be equivalent.
// is1 should equal is2
std::vector<foo> is1 = fmap(std::bind(to_foo, std::bind(to_double, _1)), is);
std::vector<foo> is2 = fmap(to_foo, fmap(to_double, is));
18
Paul Fultz II

ここで私は私の問題を解決するためのFunctorを使用することを余儀なくされた実際の状況は次のとおりです。

私は、関数の集合(たとえば、それらの20)を持ち、それぞれが3つの特定のスポットで別の特定の機能を呼び出す除き、それらは、すべて同じです。

これは信じられないほどの廃棄物、およびコードの重複です。通常、私はちょうど、関数ポインタを渡すだろう、とわずか3つのスポットでそれを呼び出します。 (だから、コードは代わりに20回の、一度に表示されている必要があります。)

しかし、私は、それぞれの場合に、特定の機能が完全に異なるパラメータプロファイルを必要と実現しました!時には2つのパラメータ、時には5つのパラメータなど.

別の解決策は、特定の機能を派生クラスでオーバーライドされたメソッドであるベースクラスを持っているだろう。しかし、私は本当にちょうどので、私は関数ポインタを渡すことができ、この継承のすべてを構築したいん????

解決策:だから私がしたことは、私が呼び出した必要な関数を呼び出すことができるラッパークラス( "Functor")を作ったことです。私は(そのパラメータを有する、など)事前にそれを設定した後、私の代わりに、関数ポインタに渡します。今と呼ばれるコードが内部で何が起こっているかを知らなくても、ファンクタをトリガすることができます。それも、複数回呼び出すことができます(私は3回を呼び出すためにそれを必要としていました。)


それはそれだ - ファンクタは私が1に20個の関数からのコードの重複を削減することができ明白かつ簡単な解決策であることが判明した実用的な例。

9
Fellow Traveler

コールバックで使用される場合を除いて、C++ファンクタは Matlab に似たアクセススタイルを matrix クラスに提供するのを助けることができます。 example があります。

3
Yantao Xie

繰り返してきたように、関数子は関数として扱うことができるクラスです(overload operator())。

これらは、あるデータを関数の繰り返しまたは遅延呼び出しに関連付ける必要がある場合に最も役立ちます。

たとえば、リンクされたファンクタリストを使用して、基本的な低オーバーヘッドの同期コルーチンシステム、タスクディスパッチャ、または割り込み可能なファイル解析を実装できます。例:

/* prints "this is a very simple and poorly used task queue" */
class Functor
{
public:
    std::string output;
    Functor(const std::string& out): output(out){}
    operator()() const
    {
        std::cout << output << " ";
    }
};

int main(int argc, char **argv)
{
    std::list<Functor> taskQueue;
    taskQueue.Push_back(Functor("this"));
    taskQueue.Push_back(Functor("is a"));
    taskQueue.Push_back(Functor("very simple"));
    taskQueue.Push_back(Functor("and poorly used"));
    taskQueue.Push_back(Functor("task queue"));
    for(std::list<Functor>::iterator it = taskQueue.begin();
        it != taskQueue.end(); ++it)
    {
        *it();
    }
    return 0;
}

/* prints the value stored in "i", then asks you if you want to increment it */
int i;
bool should_increment;
int doSomeWork()
{
    std::cout << "i = " << i << std::endl;
    std::cout << "increment? (enter the number 1 to increment, 0 otherwise" << std::endl;
    std::cin >> should_increment;
    return 2;
}
void doSensitiveWork()
{
     ++i;
     should_increment = false;
}
class BaseCoroutine
{
public:
    BaseCoroutine(int stat): status(stat), waiting(false){}
    void operator()(){ status = perform(); }
    int getStatus() const { return status; }
protected:
    int status;
    bool waiting;
    virtual int perform() = 0;
    bool await_status(BaseCoroutine& other, int stat, int change)
    {
        if(!waiting)
        {
            waiting = true;
        }
        if(other.getStatus() == stat)
        {
            status = change;
            waiting = false;
        }
        return !waiting;
    }
}

class MyCoroutine1: public BaseCoroutine
{
public:
    MyCoroutine1(BaseCoroutine& other): BaseCoroutine(1), partner(other){}
protected:
    BaseCoroutine& partner;
    virtual int perform()
    {
        if(getStatus() == 1)
            return doSomeWork();
        if(getStatus() == 2)
        {
            if(await_status(partner, 1))
                return 1;
            else if(i == 100)
                return 0;
            else
                return 2;
        }
    }
};

class MyCoroutine2: public BaseCoroutine
{
public:
    MyCoroutine2(bool& work_signal): BaseCoroutine(1), ready(work_signal) {}
protected:
    bool& work_signal;
    virtual int perform()
    {
        if(i == 100)
            return 0;
        if(work_signal)
        {
            doSensitiveWork();
            return 2;
        }
        return 1;
    }
};

int main()
{
     std::list<BaseCoroutine* > coroutineList;
     MyCoroutine2 *incrementer = new MyCoroutine2(should_increment);
     MyCoroutine1 *printer = new MyCoroutine1(incrementer);

     while(coroutineList.size())
     {
         for(std::list<BaseCoroutine *>::iterator it = coroutineList.begin();
             it != coroutineList.end(); ++it)
         {
             *it();
             if(*it.getStatus() == 0)
             {
                 coroutineList.erase(it);
             }
         }
     }
     delete printer;
     delete incrementer;
     return 0;
}

もちろん、これらの例自体はそれほど役に立ちません。それらは、ファンクタがいかに有用であり得るかを示すだけであり、ファンクタそれら自身は非常に基本的で柔軟性がなく、そしてこれは例えばブーストが提供するものよりそれらをあまり有用にしない。

2
nfries88

Functorはgtkmmで実際のC++の関数やメソッドにGUIのボタンをつなぐために使われます。


アプリをマルチスレッド化するためにpthreadライブラリを使用する場合は、Functorsが役に立ちます。
スレッドを開始するためのpthread_create(..)の引数の1つは、自分のスレッドで実行される関数ポインタです。
しかし、不便があります。このポインタは、それが静的メソッドでない限り、またはクラスの指定でない限り、メソッドへのポインタにはできません(class::methodなど)。そしてもう一つ、あなたのメソッドのインターフェースは、

void* method(void* something)

ですから、余分なことをしない限り、スレッド内で自分のクラスのメソッドを(単純で明白な方法で)実行することはできません。

C++でスレッドを処理するための非常に良い方法は、独自のThreadクラスを作成することです。 MyClassクラスからメソッドを実行したい場合、私がしたことは、それらのメソッドをFunctor派生クラスに変換することです。

また、Threadクラスはこのメソッドを持っています:static void* startThread(void* arg)
このメソッドへのポインタは、pthread_create(..)を呼び出すための引数として使用されます。そしてstartThread(..)がargで受け取るべきものは、任意のFunctor派生クラスのヒープ内のインスタンスへのvoid*キャスト参照です。これは実行時にFunctor*にキャストバックされ、それをrun()メソッドと呼びます。

2
erandros

関数をファンクタとして実装する大きな利点は、それらが呼び出しの間に状態を維持し再利用できることです。たとえば、文字列間の Levenshtein距離 を計算するための Wagner-Fischerアルゴリズム のような多くの動的計画法アルゴリズムは、大きな結果表を埋めることによって機能します。関数が呼び出されるたびにこのテーブルを割り当てることは非常に非効率的です。そのため、関数をファンクタとして実装し、テーブルをメンバ変数にすると、パフォーマンスが大幅に向上します。

以下は、ファンクタとしてWagner-Fischerアルゴリズムを実装する例です。テーブルがコンストラクタ内でどのように割り当てられ、必要に応じてサイズ変更してoperator()で再利用されるかに注意してください。

#include <string>
#include <vector>
#include <algorithm>

template <typename T>
T min3(const T& a, const T& b, const T& c)
{
   return std::min(std::min(a, b), c);
}

class levenshtein_distance 
{
    mutable std::vector<std::vector<unsigned int> > matrix_;

public:
    explicit levenshtein_distance(size_t initial_size = 8)
        : matrix_(initial_size, std::vector<unsigned int>(initial_size))
    {
    }

    unsigned int operator()(const std::string& s, const std::string& t) const
    {
        const size_t m = s.size();
        const size_t n = t.size();
        // The distance between a string and the empty string is the string's length
        if (m == 0) {
            return n;
        }
        if (n == 0) {
            return m;
        }
        // Size the matrix as necessary
        if (matrix_.size() < m + 1) {
            matrix_.resize(m + 1, matrix_[0]);
        }
        if (matrix_[0].size() < n + 1) {
            for (auto& mat : matrix_) {
                mat.resize(n + 1);
            }
        }
        // The top row and left column are prefixes that can be reached by
        // insertions and deletions alone
        unsigned int i, j;
        for (i = 1;  i <= m; ++i) {
            matrix_[i][0] = i;
        }
        for (j = 1; j <= n; ++j) {
            matrix_[0][j] = j;
        }
        // Fill in the rest of the matrix
        for (j = 1; j <= n; ++j) {
            for (i = 1; i <= m; ++i) {
                unsigned int substitution_cost = s[i - 1] == t[j - 1] ? 0 : 1;
                matrix_[i][j] =
                    min3(matrix_[i - 1][j] + 1,                 // Deletion
                    matrix_[i][j - 1] + 1,                      // Insertion
                    matrix_[i - 1][j - 1] + substitution_cost); // Substitution
            }
        }
        return matrix_[m][n];
    }
};
2

さらに、既存の従来の方法をコマンドパターンに合わせるために関数オブジェクトを使用しました。 (OOパラダイム真OCPの美しさが感じられるところだけ)関連機能アダプター・パターンもここに追加します。

あなたのメソッドがシグネチャを持っているとします。

int CTask::ThreeParameterTask(int par1, int par2, int par3)

どのようにしてCommandパターンに適合させることができるかがわかります - そのためには、まず、関数オブジェクトとして呼び出すことができるように、メンバ関数アダプタを作成する必要があります。

注 - これは醜いので、Boostのbindヘルパーなどを使うことができるかもしれませんが、できない場合や望まない場合はこれが1つの方法です。

// a template class for converting a member function of the type int        function(int,int,int)
//to be called as a function object
template<typename _Ret,typename _Class,typename _arg1,typename _arg2,typename _arg3>
class mem_fun3_t
{
  public:
explicit mem_fun3_t(_Ret (_Class::*_Pm)(_arg1,_arg2,_arg3))
    :m_Ptr(_Pm) //okay here we store the member function pointer for later use
    {}

//this operator call comes from the bind method
_Ret operator()(_Class *_P, _arg1 arg1, _arg2 arg2, _arg3 arg3) const
{
    return ((_P->*m_Ptr)(arg1,arg2,arg3));
}
private:
_Ret (_Class::*m_Ptr)(_arg1,_arg2,_arg3);// method pointer signature
};

また、呼び出しを補助するために上記のクラス用のヘルパーメソッドmem_fun3が必要です。

template<typename _Ret,typename _Class,typename _arg1,typename _arg2,typename _arg3>
mem_fun3_t<_Ret,_Class,_arg1,_arg2,_arg3> mem_fun3 ( _Ret (_Class::*_Pm)          (_arg1,_arg2,_arg3) )
{
  return (mem_fun3_t<_Ret,_Class,_arg1,_arg2,_arg3>(_Pm));

}

さて、パラメータをバインドするために、バインダ関数を書く必要があります。だから、ここに行きます:

template<typename _Func,typename _Ptr,typename _arg1,typename _arg2,typename _arg3>
class binder3
{
public:
//This is the constructor that does the binding part
binder3(_Func fn,_Ptr ptr,_arg1 i,_arg2 j,_arg3 k)
    :m_ptr(ptr),m_fn(fn),m1(i),m2(j),m3(k){}

 //and this is the function object 
 void operator()() const
 {
        m_fn(m_ptr,m1,m2,m3);//that calls the operator
    }
private:
    _Ptr m_ptr;
    _Func m_fn;
    _arg1 m1; _arg2 m2; _arg3 m3;
};

そして、バインダ3クラスを使うためのヘルパー関数 - bind3:

//a helper function to call binder3
template <typename _Func, typename _P1,typename _arg1,typename _arg2,typename _arg3>
binder3<_Func, _P1, _arg1, _arg2, _arg3> bind3(_Func func, _P1 p1,_arg1 i,_arg2 j,_arg3 k)
{
    return binder3<_Func, _P1, _arg1, _arg2, _arg3> (func, p1,i,j,k);
}

さて、これをCommandクラスで使わなければなりません。次のtypedefを使用してください。

typedef binder3<mem_fun3_t<int,T,int,int,int> ,T* ,int,int,int> F3;
//and change the signature of the ctor
//just to illustrate the usage with a method signature taking more than one parameter
explicit Command(T* pObj,F3* p_method,long timeout,const char* key,
long priority = PRIO_NORMAL ):
m_objptr(pObj),m_timeout(timeout),m_key(key),m_value(priority),method1(0),method0(0),
method(0)
{
    method3 = p_method;
}

これを呼び出す方法は次のとおりです。

F3 f3 = PluginThreadPool::bind3( PluginThreadPool::mem_fun3( 
      &CTask::ThreeParameterTask), task1,2122,23 );

注:f3();メソッドtask1-> ThreeParameterTask(21,22,23);を呼び出します。

このパターンの完全な文脈は、 link にあります。

2
Alex Punnen

Functorは、関数内のローカル関数の定義をシミュレートするためにも使用できます。 質問 および another を参照してください。

しかし、ローカルのファンクタは外部の自動変数にアクセスすることはできません。ラムダ(C++ 11)関数はより良い解決策です。

1
Yantao Xie