関数を引数として別の関数に渡すさまざまな方法の違いは何ですか?


8

1つの関数がいくつかの可能な関数の1つを呼び出す状況があります。これは、関数をパラメーターとして渡すのに適した場所のようです。ZubkovによるこのQuoaraの回答では、これを行う3つの方法があります。

int g(int x(int)) { return x(1); }
int g(int (*x)(int)) { return x(1); }
int g(int (&x)(int)) { return x(1); }
...
int f(int n) { return n*2; }
g(f); // all three g's above work the same

いつどの方法を使用する必要がありますか?違いは何ですか?私は最も単純なアプローチを好むので、なぜ最初の方法が常に使用されるべきではないのですか?

私の状況では、関数は1回だけ呼び出されますが、簡単にしたいと思います。私はそれをポインタ渡しで使用していて、最後に呼び出される関数がg(myFunc)どこにmyFuncあるかを呼び出すだけです。


3
そのなかで何も。テンプレートパラメータを使用します。
LF

2
最初の2つは完全に同等です。3つ目は、最初の2つとほぼ同じですが、左辺値が必要です。g(+f);最初の2つでは機能しますが、3つ目では機能しません。
Raymond Chen

@RaymondChen「最初の2つは完全に同等です」それから私の見解では、最初の方が単純なので、明らかに正しい選択です。なぜそれをポインターで複雑にするのですか?
ノーザン

1
一方、ではint g(int x(int))xポインタのようには見えませんが、はポインタです。対応するグローバル宣言int x(int);は、関数ポインターではなく関数を宣言します。
Raymond Chen、

@RaymondChenの主張をバックアップするためのゴッドボルトリンク。放出されたアセンブリxもポインタとしてラベル付けされることに注意してください。
Eric

回答:


3

LFのコメントを拡張すると、多くの場合、関数ポインターを完全に避け、呼び出し可能なオブジェクト(を定義するものoperator())の観点から作業する方が良いでしょう。次のすべてがそれを可能にします:

#include <type_traits>

// (1) unrestricted template parameter, like <algorithm> uses
template<typename Func>
int g(Func x) { return x(1); }

// (2) restricted template parameter to produce possibly better errors
template<
    typename Func,
    typename=std::enable_if_t<std::is_invocable_r_v<int, Func, int>>
>
int g(Func x) { return std::invoke(x, 1); }

// (3) template-less, trading a reduction in code size for runtime overhead and heap use
int g(std::function<int(int)> x) { return x(1); }

重要な点として、これらのすべては、オプションとは異なり、キャプチャを備えたラムダ関数で使用できます。

int y = 2;
int ret = g([y](int v) {
    return y + v;
});

これらはどのように呼ばれますか?また、これらはどのように優れていますか?
ノーザン

これらは、上記の署名とまったく同じ方法で呼び出されます。ラムダやその他のステートフル関数を使用するため、より優れています。すべての人<algorithm>がこのアプローチを使用してコールバック関数を受け入れることに注意してください。
Eric

OK。確認するには、テンプレート識別子を使用してテンプレート関数を呼び出す必要はありませんか?たとえば、あなたはg<int>(myFunc)単に必要ではありませg(myFunc)んか?
ノーザン

正しい、アイデアはtyoeパラメータを推測させることです
Eric

複数の関数をパラメーターとして渡しても、テンプレートは機能しますか?
北部
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.