web-dev-qa-db-ja.com

c ++-<未解決のオーバーロード関数タイプ>

Matというクラスに、別の関数をパラメーターとして受け取る関数が必要です。現在、以下の4つの関数がありますが、print()を呼び出すとエラーが発生します。 2行目はエラーになりますが、最初の行が機能するため、理由はわかりません。唯一の違いは、関数fはクラスMatのメンバーではありませんが、_f2_はメンバーです。失敗は:error: no matching function for call to Mat::test( < unresolved overloaded function type>, int)'

_template <typename F>
int Mat::test(F f, int v){
    return f(v);
}

int Mat::f2(int x){
    return x*x;
}

int f(int x){
    return x*x;
}

void Mat::print(){
    printf("%d\n",test(f ,5));    // works
    printf("%d\n",test(f2 ,5));    // does not work
}
_

なぜこれが起こるのですか?

28
Mordrag

_pointer-to-member-function_のタイプは_pointer-to-function_とは異なります。

関数の型は、それが通常の関数であるか、クラスの非静的メンバー関数であるかによって異なります。

_int f(int x);
the type is "int (*)(int)" // since it is an ordinary function
_

そして

_int Mat::f2(int x);
the type is "int (Mat::*)(int)" // since it is a non-static member function of class Mat
_

注:クラスFredの静的メンバー関数である場合、その型は通常の関数である場合と同じです:"int (*)(char,float)"

C++では、メンバー関数には、オブジェクト(メンバー関数内のthisポインター)を指す暗黙的なパラメーターがあります。通常のC関数は、メンバー関数とは異なる呼び出し規則を持っていると考えることができます。そのため、ポインターのタイプ(メンバー関数へのポインターと関数へのポインター)は異なり、互換性がありません。 C++は、メンバーへのポインターと呼ばれる新しいタイプのポインターを導入します。これは、オブジェクトを提供することによってのみ呼び出すことができます

注:メンバー関数へのポインターを関数へのポインターに「キャスト」しようとしないでください。結果は未定義であり、おそらく悲惨です。例えば、メンバー関数へのポインターは、適切な関数のマシンアドレスを含む必要はありません。前の例で述べたように、通常のC関数、トップレベル(非メンバー)関数、または静的(クラス)メンバー関数のいずれかを使用します。

これについての詳細 ここ および ここ

39
user995502

ここでの問題は、f2Matのメソッドであるのに対し、fは単なる無料の関数であるということです。 f2を単独で呼び出すことはできません。呼び出すにはMatのインスタンスが必要です。これを回避する最も簡単な方法は次のとおりです。

printf("%d\n", test([=](int v){return this->f2(v);}, 5));

そこの=thisをキャプチャします。これはf2と呼ぶ必要があります。

5
Barry