[英]Functional composition with variadic templates
我的目標是使用這種確切的語法來組合函數:
int main() {
Function<std::string, int> f([](const std::string& s) {return s.length();});
Function<int, double> g([](int x) {return x + 0.5;});
Function<double, int> h([](double d) {return int(d+1);});
std::cout << compose(g, f, "hello") << '\n'; // g(f("hello")) = 5.5
std::cout << compose(h, g, f, "hello") << '\n'; // h(g(f("hello"))) = 6
}
通過稍微改變語法以便首先使用"hello"
參數,我可以使用以下代碼輕松地進行操作:
#include <iostream>
#include <functional>
#include <tuple>
#include <string>
template <typename D, typename R>
struct Function {
using domain = const D&;
using range = R;
using function = std::function<range(domain)>;
const function& f;
Function (const function& f) : f(f) {}
range operator()(domain x) const {return f(x);}
};
template <typename... Ts>
struct LastType {
using Tuple = std::tuple<Ts...>;
using type = typename std::tuple_element<std::tuple_size<Tuple>::value - 1, Tuple>::type;
};
template <typename F, typename G>
typename G::range compose (const typename F::domain& x, const G& g, const F& f) {
return g(f(x));
}
template <typename F, typename... Rest>
auto compose (const typename LastType<Rest...>::type::domain& x, const F& f, const Rest&... rest) {
return f(compose(x, rest...));
}
int main() {
Function<std::string, int> f([](const std::string& s) {return s.length();});
Function<int, double> g([](int x) {return x + 0.5;});
Function<double, int> h([](double d) {return int(d+1);});
std::cout << compose("hello", g, f) << '\n'; // g(f("hello")) = 5.5
std::cout << compose("hello", h, g, f) << '\n'; // h(g(f("hello"))) = 6
}
完成后,我認為調整上面的代碼是一項微不足道的任務,以便我得到我想要的確切語法(即“hello”在列表的末尾),但它變得比我想象的更難。 我嘗試了以下,但不編譯:
#include <iostream>
#include <functional>
#include <tuple>
#include <string>
template <typename D, typename R>
struct Function {
using domain = const D&;
using range = R;
using function = std::function<range(domain)>;
const function& f;
Function (const function& f) : f(f) {}
range operator()(domain x) const {return f(x);}
};
template <typename F, typename G>
typename G::range compose (const G& g, const F& f, const typename F::domain& x) {
return g(f(x));
}
template <typename F, typename... Rest>
auto compose (const F& f, const Rest&... rest) {
return f(compose(rest...));
}
int main() {
Function<std::string, int> f([](const std::string& s) {return s.length();});
Function<int, double> g([](int x) {return x + 0.5;});
Function<double, int> h([](double d) {return int(d+1);});
std::cout << compose(g, f, "hello") << '\n'; // g(f("hello")) = 5.5
std::cout << compose(h, g, f, "hello") << '\n'; // h(g(f("hello"))) = 6
}
我不知道如何解決它。 任何人都可以幫我解決這個問題嗎?
我想出的一個新想法是定義compose_
,它將重新排序args...
(通過一些std::tuple
操作),以便第一個元素最后一個然后傳遞該參數包來compose
。 這看起來非常混亂,即使它有效,也必須有一個更直接(和更短)的解決方案。
看起來以下也適用:
template <typename T>
const T& compose (const T& t) {
return t;
}
template <typename F, typename... Rest>
typename F::range compose(const F& f, Rest... rest) {
return f(compose(rest...));
}
這樣怎么樣?
#include <iostream>
#include <functional>
#include <tuple>
#include <string>
template <typename D, typename R>
struct Function {
using domain = const D&;
using range = R;
using function = std::function<range(domain)>;
const function& f;
Function (const function& f) : f(f) {}
range operator()(domain x) const {return f(x);}
};
template <typename F, typename X = typename F::domain>
typename F::range compose (const F& f, const X & x) {
return f(x);
}
template <typename F, typename... Rest>
typename F::range compose (const F& f, const Rest&... rest) {
return f(compose(rest...));
}
int main() {
Function<std::string, int> f([](const std::string& s) {return s.length();});
Function<int, double> g([](int x) {return x + 0.5;});
Function<double, int> h([](double d) {return int(d+1);});
std::cout << compose(g, f, "hello") << '\n'; // g(f("hello")) = 5.5
std::cout << compose(h, g, f, "hello") << '\n'; // h(g(f("hello"))) = 6
}
你可以在c ++ 14中使用auto
作為返回類型的compose()
(如果我沒錯的話)。
您的版本無法編譯,因為當最終(不是varidic)使用2個類型和3個參數時,
compose()
可變版本使用N個可變參數類型和N個參數。
換句話說,可變版本失去了最后的論點。
您的版本無法編譯,因為從不使用最終版本(非可變版本):編譯器選擇可變參數版本。 添加typename X = typename F::domain
(並更改const typename F::domain&
with const X&
)最終版本是首選,您的代碼應該編譯(至少使用c ++ 14)[由Piotr Skotnicki修正; 謝謝]
ps:抱歉我的英語不好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.