問題
我有一個函式double subs(std::function<double(double)> func),我想將它包裝在一個看起來像這樣的新函式中
template<typename... Args> double subsWrap(std::function<double(Args... args)> func)
這適用subs于一些需要更多輸入的函式
subs( subs( subs( ... func(...) ) ) )
每次subs僅適用于 的一個論點func。
最小的例子
假設我們有一個函式
auto subs = [] (std::function<double(double)> func){return func(2) func(5.3);};
我們想把它應用到
auto f2=[](double x, double y){return std::sin(x*std::exp(x/y)); };
作為
subs( [&f2](double y){ return subs( [&y,&f2](double x){ return f2(x,y); } ); } )
因為f2,這很容易,所以不需要包裝器。但是,如果我們想對具有更多引數(例如double(double,double,double,double,double))的函式做同樣的事情,事情就會變得復雜。
必須有一種方法可以自動執行此操作,但我什至不知道如何開始。
uj5u.com熱心網友回復:
使用可變引數 lambda 和std::is_invocable型別特征來終止遞回怎么樣?
template<class Fn>
double subs_wrap(Fn func) {
if constexpr (std::is_invocable_v<Fn, double>)
return subs(func);
else
return subs([=](double x) {
return subs_wrap(
[=](auto... xs) -> decltype(func(x, xs...))
{ return func(x, xs...); }
);
});
}
這里需要一個 lambda 的顯式回傳型別規范來傳播“可呼叫性”屬性。[=](auto... xs) { return func(x, xs...); }可以用任意數量的引數正式呼叫,無論是否func(x, xs...)可呼叫。當使用 明確指定回傳型別時decltype,SFINAE 會跳入。
有了這個實作,兩個運算式
subs([=](double y) {
return subs([=](double x) {
return f2(x, y);
});
});
和
subs_wrap(f2);
將產生相同的結果。
有趣的是,通過-O3優化,GCC 和 Clang 都可以優化所有這些代碼并替換subs_wrap(f2)為編譯時常量。對于使用std::function引數撰寫的類似代碼,他們不會這樣做。
如果我們想將引數傳遞給 subs,我們如何進行解包(每個遞回都不同)
這是一種通過稍微修改代碼來實作此目的的方法:
template<class Fn, class P, class... Ps>
double subs_wrap(Fn func, P p, Ps... ps) {
if constexpr (std::is_invocable_v<Fn, double>) {
static_assert(sizeof...(Ps) == 0);
return subs(func, p);
}
else {
static_assert(sizeof...(Ps) > 0);
return subs([=](double x) {
return subs_wrap(
[=](auto... xs) -> decltype(func(x, xs...))
{ return func(x, xs...); },
ps...);
}, p);
}
}
subs_wrap(f2, p1, p2);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/459556.html
上一篇:在C 中初始化模板類私有靜態變數
