0

私はいくつかのコードで遊んでいて、いくつかのことに少し戸惑っています。簡単な例を次に示します。

Nodes算術演算(加算、減算など)を実行します。プログラムで使用できるさまざまな操作を含むコンテナーがあります。次に例を示します。

typedef std::binary_function<double, std::vector<double>&, std::vector<Node*>& > my_binary_function;
auto const & product = [](double v, Node* n){ return v * n->GetEvaluation(); };
struct addition : public my_binary_function {
double
    operator()(std::vector<double>& weights, std::vector<Node*>& subtrees) {
        return std::inner_product(weights.begin(), weights.end(), 
        subtrees.begin(), 0, std::plus<double>(), product);
    }
};

さて、この時点で 2 つの選択肢があります。

1) 関数型を使用します。

typedef double (*my_function)(std::vector<double>&, std::vector<Node*>&);

次に、次のテンプレート関数を使用してファンクターを変換します。

template<typename F> typename F::result_type
func(typename F::first_argument_type arg1, typename F::second_argument_type arg2) {
    return F()(arg1, arg2);
}

2)関数ラッパータイプ、つまりstd::functionを使用して、私が持っているようにします

typedef std::function<double (std::vector<double>&, std::vector<Node*>&)> my_function;

要約すると、次のようになります。

LoadDefaultFunctions() {
    int minArity = 2;
    int maxArity = 2;
    function_set_.AddFunction("Add", func<addition> , minArity, maxArity, 1.0); // case 1
OR
    function_set_.AddFunction("Add", addition(), minArity, maxArity, 1.0); // case 2

そして今問題:

a) 方法 1 を使用すると、次のコンパイル エラーが発生します。

error: invalid initialization of non-const reference of type 
'std::binary_function<double, std::vector<double>&, 
std::vector<Node*>&>::result_type {aka std::vector<Node*>&}' 
from an rvalue of type 'double'

テンプレートを変更すると、エラーはなくなります (引数が実際には意味をなさないことに注意してください)。

template <typename F> typename F::first_argument_type
func1(typename F::second_argument_type arg1, typename F::result_type arg2) {
    return F()(arg1, arg2); 
}

binary_op<double, double, double>などの他のタイプでは、最初の形式が正常に機能するため、非常に奇妙に思います。それで、何が起こっているのですか?

b) 1) は 2) よりも高速です (わずかな差で)。std::functionファンクターを参照渡しするか、より効率的にラップできるようにする何らかの方法でファンクターを渡すという巧妙なトリックがおそらく欠けていると思います。何か案は?

c) 2) の typedef を使用するが、さらにfuncファンクターから関数を生成するために使用しstd::function、それを処理する場合でも、2) よりも高速です。あれは:

`my_function = func<addition>` is faster than `my_function = addition()`

誰かがこのすべての背後にあるメカニズムを理解するのを手伝ってくれたら本当にありがたい.

ありがとう。

4

1 に答える 1

2

b) 1) は 2) よりも高速です (わずかな差で)。ファンクターを参照渡しする、または std::function をより効率的にラップできるようにする何らかの方法で、ファンクターを渡すという巧妙なトリックがおそらく欠けていると思います。何か案は?

はい、1 は 2 よりも高速であると予想します。仮想関数呼び出しの使用を必要とする型std::function消去 (格納されたcallableの正確な型は外側の型には存在しません) を実行します。std::function一方、テンプレートを使用すると、正確な型がわかっているため、コンパイラが呼び出しをインライン化する可能性が高くなり、無料のソリューションになります。これは、ファンクターを渡す方法とは関係ありません。

エラー

テンプレート引数の順序が正しくありません:

typedef std::binary_function<double,                 // arg1
                             std::vector<double>&,   // arg2
                             std::vector<Node*>&     // return type
                            > my_binary_function;

struct addition : public my_binary_function {
    double                                           // return type
    operator()( std::vector<double>& weights,        // arg1 
                std::vector<Node*>& subtrees)        // arg2
    { ...

つまり、からの継承によってbinary_functionクラスにいくつかの typedef が追加されますが、それらは正しい typedef ではありません。次に、次のテンプレートで typedef を使用すると、型が一致しません。operator()テンプレートは、あなたが a を返すことを期待していますがstd::vector<Node*>&、それは の戻り値の型ですfuncが、ファンクターを呼び出すとdouble、エラーにつながる a が得られます:

std::vector<Node*>&...からの無効な初期化double

于 2012-05-20T00:06:45.257 に答える