0

C++11 や Boost は使用していません。ファンクターを使用して std::for_each などのアルゴリズムに渡したいのですが、関数の外でファンクターを定義しなければならないのは面倒です。使用する直前に関数内でローカルに定義したい。ただし、以下は機能しません。これは古い C++ 標準によるもので、ローカルで定義されたクラスをテンプレート パラメーターとして使用することを許可していません (C++11 で修正されました)。

int main()
{
    std::vector<int> v(10);

    class SetInc
    {
    public:
        SetInc() : x(0) {}

        virtual void operator () (int& a)
        {
            a = x++;
        }

    private:
        int x;
    } f;

    std::for_each(v.begin(), v.end(), f);

    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, "\n"));
}

しかし、私は次の回避策を開発しました。

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <iterator>

template <typename ARGUEMENT, typename RESULT>
class FunctorBase
{
public:
    typedef ARGUEMENT argument_type;
    typedef RESULT result_type;

    virtual result_type operator () (argument_type) = 0;
    FunctorBase() {}
    virtual ~FunctorBase() {}
};

template <typename ARGUEMENT, typename RESULT>
class FunctorWrapper
{
public:
    typedef ARGUEMENT argument_type;
    typedef RESULT result_type;
    typedef FunctorBase<argument_type, result_type> Functor_T;

    explicit FunctorWrapper(Functor_T *functor)
        : functor(functor)
    {}

    result_type operator () (argument_type a)
    {
        return (*functor)(a);
    }

private:
    Functor_T *functor;
};

template <typename ARGUEMENT, typename RESULT>
FunctorWrapper<ARGUEMENT, RESULT> make_unary_functor(FunctorBase<ARGUEMENT, RESULT>& f)
{
    return FunctorWrapper<ARGUEMENT, RESULT>(&f);
}

int main()
{
    std::vector<int> v(10);

    class SetInc : public FunctorBase<int&, void>
    {
    public:
        SetInc() : x(0) {}

        virtual result_type operator () (argument_type a)
        {
            a = x++;
        }

    private:
        int x;
    } f;

    std::for_each(v.begin(), v.end(), make_unary_functor(f));

    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, "\n"));
}

それはいいですか?

4

3 に答える 3

2

問題は、C++ 98 では、外部バインディングのない型はテンプレート パラメーターにできないことです。そのため、SetInc を名前のない名前空間に配置するのが最善の方法です。

回避策が移植可能な方法で問題を解決するかどうかはわかりませんが、理解するのはさらに困難です (回避策にコメントして、なぜこのようにしたのかを人々が理解できるようにする必要があります)。コンパイラが仮想関数呼び出しを最適化するのははるかに困難です。

于 2013-03-21T17:23:24.437 に答える
1

1 つの明確な問題は、仮想関数呼び出しです。通常の関数オブジェクトでは、呼び出された関数をインライン化できます。おそらくそうではありません。そのため、小さな関数のオーバーヘッドが大幅に増加します。

于 2013-03-21T17:27:30.370 に答える
0

仮想関数を定義する必要はありません。ポリモーフィズムはありません。あなたのコードはすべて良いですが、STLの方が優れています=)

ここを見て

http://www.cplusplus.com/reference/functional/binary_function/

http://www.cplusplus.com/reference/functional/unary_function/

例のセクションで

struct IsOdd : public std::unary_function<int,bool> {
  bool operator() (int number) {return (number%2==1);}
};

PS: ファンクターをコピーせずにラッパーを使用したい場合は、このように書き直してください。

テンプレート

class FunctorWrapper
{
public:
    typedef F::argument_type argument_type;
    typedef F::result_type result_type;

explicit FunctorWrapper(F *functor)
    : functor(functor)
{}

result_type operator () (argument_type const & a) const
{
    return (*functor)(a);
}

result_type operator () (argument_type & a) const
{
    return (*functor)(a);
}

private:
    F *functor;
};

template <typename F>
FunctorWrapper<F> make_unary_functor(F& f)
{
    return FunctorWrapper<ARGUEMENT, RESULT>(&f);
}
于 2013-03-21T17:23:11.927 に答える