[英]function composition in C++ / C++11
我目前正在編寫一些需要大量函數組合的C ++ 11中的加密算法。 我必須處理兩種類型的構圖:
自己編寫一個函數可變次數。 在數學上,對於某個函數F,F ^ n(x)=(F ^ {n-1} o F)(x)= F ^ {n-1}(F(x))。
一起組合不同的功能。 例如,對於相同類型的一些函數f,g,h,i,j和k,我將具有f(g(h(i(j(k(x))))))。
就我而言,我使用的是F的以下定義:
const std::vector<uint8_t> F(const std::vector<uint8_t> &x);
我想自己組合這個功能n次。 我已經以一種簡單的遞歸方式實現了組合,它工作正常:
const std::vector<uint8_t> compose(const uint8_t n, const std::vector<uint8_t> &x)
{
if(n > 1)
return compose(n-1, F(x));
return F(x);
}
對於這種情況,是否有一種更有效的方法來使用c ++ 11實現此組合但不使用BOOST ? 如果可能的話,使用這個表格會很棒:
answer = compose<4>(F)(x); // Same as 'answer = F^4(x) = F(F(F(F(x))))'
對於第二種情況,我想實現可變數量的函數的組合。 對於給定的一組函數F0,F1,...,Fn具有與F相同的定義,是否有一種有效且合適的方法來組合它們,其中n是可變的? 我認為可變參數模板在這里很有用,但在這種情況下我不知道如何使用它們。
謝謝你的幫助。
沿着這些方向的東西,也許(未經測試):
template <typename F>
class Composer {
int n_;
F f_;
public:
Composer(int n, F f) : n_(n), f_(f) {}
template <typename T>
T operator()(T x) const {
int n = n_;
while (n--) {
x = f_(x);
}
return x;
}
};
template <int N, typename F>
Composer<F> compose(F f) {
return Composer<F>(N, f);
}
編輯:對於第二種情況( 這次測試 ):
#include <iostream>
template <typename F0, typename... F>
class Composer2 {
F0 f0_;
Composer2<F...> tail_;
public:
Composer2(F0 f0, F... f) : f0_(f0), tail_(f...) {}
template <typename T>
T operator() (const T& x) const {
return f0_(tail_(x));
}
};
template <typename F>
class Composer2<F> {
F f_;
public:
Composer2(F f) : f_(f) {}
template <typename T>
T operator() (const T& x) const {
return f_(x);
}
};
template <typename... F>
Composer2<F...> compose2(F... f) {
return Composer2<F...>(f...);
}
int f(int x) { return x + 1; }
int g(int x) { return x * 2; }
int h(int x) { return x - 1; }
int main() {
std::cout << compose2(f, g, h)(42);
return 0;
}
感謝有趣的問題,2013年的Gabriel。這是一個解決方案。 它適用於c ++ 14。
#include <functional>
#include <iostream>
using std::function;
// binary function composition for arbitrary types
template <class F, class G>
auto compose(F f, G g){
return [f,g](auto x){return f(g(x));};
}
// for convienience
template <class F, class G>
auto operator*(F f, G g){
return compose(f,g);
}
// composition for n arguments
template <class F, typename... Fs>
auto compose(F f, Fs&&... fs) {
return f * compose(fs...);
}
// composition for n copies of f
template <int i, class F>
//must wrap chain in a struct to allow partial template specialization
struct multi { static F chain(F f){
return f * multi<i-1,F>::chain(f);
}};
template <class F>
struct multi <2,F> { static F chain(F f){
return f * f;
}};
template <int i, class F>
F compose(F f) {return multi<i,F>::chain(f); }
int main(int argc, char const *argv[]) {
function<double(int)> f = [](auto i){return i + 3;};
function<int(double)> g = [](auto i){return i * 2;};
function<int(int) > h = [](auto i){return i + 1;};
std::cout
<< '\n' << "9 == " << compose(f,g,f) (0) \
<< '\n' << "9 == " << (f * g * h) (0) \
<< '\n' << "3 == " << compose<100>(h) (0) \
<< '\n';
return 0;
}
你可以定義
Matrix compose(Matrix f, Matrix g);
要么
Rotation compose(Rotation f, Rotation g);
為各種事情重用這個代碼。
一個非常一般的例子( g++ -std=c++1y composition.cpp
):
// ---------------------------------------------------------
// "test" part
// ---------------------------------------------------------
int f(int a) { return 2*a; }
double g(int a) { return a+2.5; }
double h(double a) { return 2.5*a; }
double i(double a) { return 2.5-a; }
class Functor {
double x;
public:
Functor (double x_) : x(x_) { }
double operator() (double a) { return a*x; }
};
// ---------------------------------------------------------
// ---------------------------------------------------------
int main () {
auto l1 = [] (double a) { return a/3; };
auto l2 = [] (double a) { return 3.5+a; };
Functor fu {4.5};
auto compos1 = compose (f, g, l1, g, h, h, l1, l2);
auto compos2 = compose (compos1, l1, l2, fu);
auto x = compos2 (3);
cout << x << endl;
cout << compos2(3) << endl;
cout << fu(l2(l1(l2(l1(h(h(g(l1(g(f(3))))))))))) << endl;
} // ()
圖書館部分:
// ---------------------------------------------------------
// "library" part
// ---------------------------------------------------------
template<typename F1, typename F2>
class Composite{
private:
F1 f1;
F2 f2;
public:
Composite(F1 f1, F2 f2) : f1(f1), f2(f2) { }
template<typename IN>
decltype(auto) operator() (IN i)
{
return f2 ( f1(i) );
}
};
// ---------------------------------------------------------
// ---------------------------------------------------------
template<typename F1, typename F2>
decltype(auto) compose (F1 f, F2 g) {
return Composite<F1, F2> {f,g};
}
// ---------------------------------------------------------
// ---------------------------------------------------------
template<typename F1, typename... Fs>
decltype(auto) compose (F1 f, Fs ... args)
{
return compose (f, compose(args...));
}
整個計划:
// g++ -std=c++1y composition.cpp
#include <iostream>
using namespace std;
// ---------------------------------------------------------
// "library" part
// ---------------------------------------------------------
template<typename F1, typename F2>
class Composite{
private:
F1 f1;
F2 f2;
public:
Composite(F1 f1, F2 f2) : f1(f1), f2(f2) { }
template<typename IN>
decltype(auto) operator() (IN i)
{
return f2 ( f1(i) );
}
};
// ---------------------------------------------------------
// ---------------------------------------------------------
template<typename F1, typename F2>
decltype(auto) compose (F1 f, F2 g) {
return Composite<F1, F2> {f,g};
}
// ---------------------------------------------------------
// ---------------------------------------------------------
template<typename F1, typename... Fs>
decltype(auto) compose (F1 f, Fs ... args)
{
return compose (f, compose(args...));
}
// ---------------------------------------------------------
// "test" part
// ---------------------------------------------------------
int f(int a) { return 2*a; }
double g(int a) { return a+2.5; }
double h(double a) { return 2.5*a; }
double i(double a) { return 2.5-a; }
class Functor {
double x;
public:
Functor (double x_) : x(x_) { }
double operator() (double a) { return a*x; }
};
// ---------------------------------------------------------
// ---------------------------------------------------------
int main () {
auto l1 = [] (double a) { return a/3; };
auto l2 = [] (double a) { return 3.5+a; };
Functor fu {4.5};
auto compos1 = compose (f, g, l1, g, h, h, l1, l2);
auto compos2 = compose (compos1, l1, l2, fu);
auto x = compos2 (3);
cout << x << endl;
cout << compos2(3) << endl;
cout << fu(l2(l1(l2(l1(h(h(g(l1(g(f(3))))))))))) << endl;
} // ()
使用參數轉發快速實現函數迭代。 遺憾的是,輔助類型是必需的,因為函數模板不能部分專門化。
#include <functional>
#include <iostream>
using namespace std;
template<int n, typename A>
struct iterate_helper {
function<A(A)> f;
iterate_helper(function<A(A)> f) : f(f) {}
A operator()(A&& x) {
return f(iterate_helper<n - 1, A>(f)(forward<A>(x)));
};
};
template<typename A>
struct iterate_helper<1, A> {
function<A(A)> f;
iterate_helper(function<A(A)> f) : f(f) {}
A operator()(A&& x) {
return f(forward<A>(x));
};
};
template<int n, typename A>
function<A(A)> iterate(function<A(A)> f) {
return iterate_helper<n, A>(f);
}
int succ(int x) {
return x + 1;
}
int main() {
auto add5 = iterate<5>(function<int(int)>(succ));
cout << add5(10) << '\n';
}
您沒有顯示F
的主體,但如果您可以修改它以使其改變輸入以形成輸出,則將簽名更改為:
void F(std::vector<uint8_t>& x);
此后,您可以將Fn實現為:
void Fn(std::vector<uint8_t>& x, size_t n)
{
for (size_t i = 0; i < n; i++)
F(x);
}
如果它更有效,編譯器將為你展開循環,但即使它不是一個局部變量的增量/比較將比調用F更快幾個數量級。
然后,當您真正想要復制時,可以使用explcitly copy-construct new vectors:
vector<uint8_t> v1 = ...;
vector<uint8_t> v2 = v1; // explicitly take copy
Fn(v2,10);
怎么樣(未經測試):
template < typename Func, typename T >
T compose_impl( Func &&, T &&x, std::integral_constant<std::size_t, 0> )
{ return std::forward<T>(x); }
template < typename Func, typename T, std::size_t N >
T compose_impl( Func &&f, T &&x, std::integral_constant<std::size_t, N> )
{
return compose_impl( std::forward<Func>(f),
std::forward<Func>(f)(std::forward<T>( x )),
std::integral_constant<std::size_t, N-1>{} );
}
template < std::size_t Repeat = 1, typename Func, typename T >
T compose( Func &&f, T &&x )
{
return compose_impl( std::forward<Func>(f), std::forward<T>(x),
std::integral_constant<std::size_t, Repeat>{} );
}
我們可以為多個函數使用可變參數函數模板(未經測試):
template < typename Func, typename T >
constexpr // C++14 only, due to std::forward not being constexpr in C++11
auto chain_compose( Func &&f, T &&x )
noexcept( noexcept(std::forward<Func>( f )( std::forward<T>(x) )) )
-> decltype( std::forward<Func>(f)(std::forward<T>( x )) )
{ return std::forward<Func>(f)(std::forward<T>( x )); }
template < typename Func1, typename Func2, typename Func3, typename ...RestAndT >
constexpr // C++14 only, due to std::forward
auto chain_compose( Func1 &&f, Func2 &&g, Func3 &&h, RestAndT &&...i_and_x )
noexcept( CanAutoWorkHereOtherwiseDoItYourself )
-> decltype( auto ) // C++14 only
{
return chain_compose( std::forward<Func1>(f),
chain_compose(std::forward<Func2>( g ), std::forward<Func3>( h ),
std::forward<RestAndT>( i_and_x )...) );
}
即將推出的decltype(auto)
構造會自動計算內聯函數的返回類型。 我不知道noexcept
是否有類似的自動計算
這是一個簡單的c ++ 14解決方案(可能會重寫為c ++ 11):
#include <iostream>
// base condition
template <typename F>
auto compose(F&& f)
{
return [a = std::move(f)](auto&&... args){
return a(std::move(args)...);
};
}
// recursive composition
// from compose(a, b, c...) to compose(ab, c...)
template <typename F1, typename F2, typename... Fs>
auto compose(F1&& f1, F2&& f2, Fs&&... fs)
{
return compose(
[first = std::move(f1), second = std::move(f2)]
(auto&&... args){
return second(first(std::move(args)...));
},
std::move(fs)...
);
}
可能的用法:
int main()
{
const auto f = compose(
[](const auto n){return n * n;},
[](const auto n){return n + 2;},
[](const auto n){return n + 2;}
);
std::cout << f(10) << std::endl; // outputs 104
}
這里有一個回購鏈接,還有一些例子: https : //github.com/nestoroprysk/FunctionComposition
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.