関数を別な変数に移して呼び出す

たまにこういうのが必要になる。

関数のオブジェクトをいったん別の変数に移し、元のオブジェクトを空にしてから、移した先の関数を呼び出す。

これが必要になるのは、コールバック関数を呼び出し、そのコールバック関数のなかでさらにコールバック関数が登録されるような状況。

元のオブジェクトを空にしているのは、クロージャによって保持されている変数の所有権を手放すことを意図している。

関数名はもっといいのがあるはず。

#include <iostream>
#include <utility>
#include <functional>

template <class R, class... Args>
R call_and_clear(std::function<R(Args...)>& f, Args&&... args)
{
    auto temp = std::move(f);
    f = nullptr;
    return temp(std::forward<Args>(args)...);
}

int main()
{
    std::function<int(int, int)> f = [](int a, int b) {
        return a + b;
    };

    std::cout << call_and_clear(f, 1, 2) << std::endl;
}

出力

3

1引数にしか対応していないけど、C#の実装はこちら:

using System;

class CallAndClear
{
    public static R Apply<R, Arg1>(ref Func<Arg1, R> f, Arg1 arg1)
    {
        var temp = f;
        f = null;
        return temp(arg1);
    }
}

class Program
{   
    static void Main(string[] args)
    {
        Func<int, int> f = x => x + 3;
        int result = CallAndClear.Apply(ref f, 2);
        Console.WriteLine(result);
    }
}

出力

5