2

2番目の例が機能しないのはなぜですか?後で参照するためにラムダまたは関数をメディアに型キャストしながら、2番目の例を機能させる方法はありますか?

// Types I'm using
typedef void (*ANY_FUNC)(...);
typedef void (*VOID_FUNC)();

これは動作します

void call_void( VOID_FUNC func) {
    ((ANY_FUNC)func)();
};

// ...

call_void([]() { /* do something */ });

これはしません

template <typename fn>
void call_any( fn func ) {
    ((ANY_FUNC)func)();
};

// ...

call_any([]() { /* do something */ });

現在の2番目の例を使用する必要がないという事実を無視してください。デモンストレーション(相対コード)専用です。

どちらの例も、ラムダの代わりに関数ポインターを使用して機能します。

4

4 に答える 4

2

テンプレートを宣言している限り、受信関数オブジェクトを直接使用できます。また、関数の引数を値ではなく参照として宣言する必要があります。

template <typename fn>
void call_any(fn&& func) {
    func();
};

引数を指定して関数を呼び出したい場合は、次のようにします。

template <typename fn, typename... Args>
void call_any_many(fn&& func, Args&&... args) {
    func(std::forward<Args>(args)...);
};

使用例:

int main ()
{
    call_void([]() { std::cout << "Hello, void World!" << std::endl; });
    call_any([]() { std::cout << "Hello, any World!" << std::endl; });
    call_any_many([](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; }, 1234);

    return 0;
}

ただし、いくつかの関数ポインターを保存し、それらを直接呼び出すのではなく、ヘッダーstd::functionから使用することをお勧めします。<functional>ここからいくつかの情報と例を見ることができます: http://en.cppreference.com/w/cpp/utility/functional/function

例えば:

#include <iostream>
#include <functional>

int main ()
{
    std::function<void()> anyf = []() { std::cout << "Hello, any World!" << std::endl; };
    std::function<void(int)> intf = [](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; };

    anyf();
    intf(1234);

    return 0;
}
于 2012-12-29T11:22:27.957 に答える
0

1つ目は、ラムダを対応する引数と戻り値を持つ関数ポインターに変換し、次にそれをvararg関数にキャストすることです。一方、2つ目は、ラムダを直接vararg関数(つまり、対応する引数タイプのない関数)に変換しようとします。

最初の例の2つの変換は許可されています*が、2番目の例の1つの変換は許可されていません。

*関数ポインタ型間の変換に使用するキャスト表記は、次のように機能することに注意してくださいreinterpret_cast。「関数ポインタは、別の型の関数ポインタに明示的に変換できます。関数へのポインタを介して関数を呼び出す効果関数の定義で使用されている型と同じではない型(8.3.5)は未定義です。」したがって、最初のサンプルコードの動作は未定義です。

于 2012-12-29T10:03:13.347 に答える
0

おそらく一部のコンパイラでの偶然を除いて、それらのどれも実際に機能するとは思いません。

ラムダとの違いは、関数ポインターに変換できることですが、関数ポインターではありません。テンプレート化されたバージョンはこの違いに気づきfnVOID_FUNC.

于 2012-12-29T09:51:03.127 に答える
0

ラムダは関数ポインタに暗黙的に変換できます (ただし、何もキャプチャしない場合のみ)。そのため、call_any のパラメータを関数ポインタに変更するだけです。

void call_any(ANY_FUNC func)
{
    (*func)();
}

適切なタイプのラムダで呼び出す必要があります。

call_any([](...) { /* ... */ });

しかし、可変長の引数リスト (別名 varargs) は、可能な限りタイプ セーフではないため、良くありません。関数ポインターと同じです。それらはオブジェクト指向ではありません。おそらく可変個引数テンプレートとポリモーフィズム (仮想メソッド) を含む代替メカニズムを考える必要があります。

于 2012-12-29T09:59:52.720 に答える