C++結合関数

4173 ワード

結合関数は、N個の一元関数をより複雑な関数として構成し、各関数の戻り値は最後の関数に伝達されるまでパラメータとして次の関数に伝達される.この組合せ関数の能力は,複雑なチェーン実行挙動をより直感的に達成することができる.たとえば、次の3つの関数があります.
int f(int x), int g(int y), int h(int z)
        
int a,b,c,parm; 
a = f(parm); 
b = g(a); 
c = h(b); 
    c = h(g(f(parm)));

この方式は使いやすくなく、これらの簡単な関数を組み合わせることができれば、簡単な関数で呼び出すことができ、より直感的で簡潔になります.たとえば、次のように呼び出されます.
compose(f,g,h)(parm);

この方式はこれらの関数を直列に接続し,内部は次々と呼び出され,最終結果が得られる.
c++でこの組合せ関数の呼び出しをどのように実現しますか?どうすればいいか考えてみましょう.まず、この組合せ関数の呼び出しの特徴を分析します.
すべて一元関数です.戻り値は次の関数のパラメータになるため、戻り値は1つの結果しかありません.
一元関数のパラメータと戻り値は同じタイプです.戻り値は次の関数のパラメータになるからです.
行き先から順番に呼び出す.
上記の解析から,この組合せ関数には,戻り値とパラメータが同じでなければならないという暗黙の制約があり,これらの関数は一元関数にすぎないことが分かった.複数のパラメータが必要な場合は、data_と同様に構造体をパラメータとして使用できます.struct f(data_struct)は、複数のパラメータの問題を実現するために使用される.
では、c++でこの呼び出しがどのように実現されているかを見てみましょう.
template 
class Composed
{
public:
	explicit Composed(OuterFn outerFn, InnerFn innerFn) :m_outerFn(outerFn), m_innerFn(innerFn) {}

public:
	template 
	auto operator()(Arg arg) -> decltype(declval()((declval()(declval()))))
	{
		return m_outerFn(m_innerFn(arg));
	}

private:
	InnerFn m_innerFn;
	OuterFn m_outerFn;
};

template 
Composed Compose(Function1 f1, Function2 f2)
{
	return Composed(f1, f2);
}

template 
auto Compose(Function1 f1, Function2 f2, Function3 f3, Functions... fs)->decltype(Compose(Compose(f1, f2), f3, fs...))
{
	return Compose(Compose(f1, f2), f3, fs...);
}

テストコード:
void TestCompose()
{
    auto f1 = [](int a){return a + 1; };
    auto g1 = [](int b){return b + 2; };
    auto h1 = [](int c){return c + 3; };
    auto I1 = [](int d){return d + 4; };
    auto J1 = [](int e){return e + 5; };

    auto ret = Compose(f1, g1, h1)(3);
    ret = Compose(f1, g1, h1, I1)(3);
    ret = Compose(f1, g1, h1, I1, J1)(3); 
    ret = Compose(f1, g1, h1, I1, J1, J1, J1)(3);
    ret = Compose([](int d){return d + 4; }, [](int d){return d + 5; })(3);

}

composeについては以前のコードはgccでコンパイルされていたが、GCCとvs 2013が変参に対する展開ルールが異なるため、GCCの展開ルールがより厳しい.
完全なテストコード:
#include 
#include 

using namespace std;
template 
class Composed
{
public:
	explicit Composed(OuterFn outerFn, InnerFn innerFn) :m_outerFn(outerFn), m_innerFn(innerFn) {}

public:
	template 
	auto operator()(Arg arg) -> decltype(declval()((declval()(declval()))))
	{
		return m_outerFn(m_innerFn(arg));
	}

private:
	InnerFn m_innerFn;
	OuterFn m_outerFn;
};

template 
Composed Compose(Function1 f1, Function2 f2)
{
	return Composed(f1, f2);
}

template 
auto Compose(Function1 f1, Function2 f2, Function3 f3, Functions... fs)->decltype(Compose(Compose(f1, f2), f3, fs...))
{
	return Compose(Compose(f1, f2), f3, fs...);
}
void TestCompose()
{
	auto f1 = [](int a){return a + 1; };
	auto g1 = [](int b){return b + 2; };
	auto h1 = [](int c){return c + 3; };
	auto I1 = [](int d){return d + 4; };
	auto J1 = [](int e){return e + 5; };

	auto ret = Compose(f1, g1, h1)(3);
	ret = Compose(f1, g1, h1, I1)(3);
	cout << ret << endl;
	ret = Compose(f1, g1, h1, I1, J1)(3);
	cout << ret << endl;
	ret = Compose(f1, g1, h1, I1, J1, J1, J1)(3);
	cout << ret << endl;
	ret = Compose([](int d){return d + 4; }, [](int d){return d + 5; })(3);
	cout << ret << endl;
}

int main()
{
	TestCompose();
	system("pause");
	return 0;
}