具有可变参数模板的功能组合
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()
(如果我没记错的话)。
compose()
版本使用 N 个可变参数类型和 N 个参数,而最终版本(非可变参数)使用 2 个类型和 3 个参数。换句话说,可变参数版本失去了最终的论点。您的版本无法编译,因为从不使用最终版本(非可变参数版本):编译器选择可变参数版本。添加typename X = typename F::domain
(并用const X&
更改const typename F::domain&
)最终版本是首选,您的代码应该编译(至少使用 c++14)[由 Piotr Skotnicki 更正;谢谢]
PS:对不起,我的英语不好。
相关文章:
- 在执行其他功能的同时播放动画(LED矩阵和Arduino/ESP8266)
- 多态性和功能结合
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 带内存和隔离功能的SQLite
- 可组合的lambda/std::函数与std::可选
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 在CMakeLists.txt的安装功能中使用.cmake文件有什么用
- 类模板的成员功能的定义在单独的TU中完全专业化
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何在C++中获得"静态纯虚拟"功能?
- 错误:(-210:不支持的格式或格式组合)功能'create'中的硬件视频解码器不支持视频源
- 有没有办法组合多个几乎相同的功能?
- 如何简化代码并将开关组合成一个功能?
- OpenCV 错误的解决方案:不支持的格式或格式组合 - 当将 ORB 功能与 FlannBasedMatcher 匹配
- 如何正确组合类型的别名,功能指针和模板功能
- 变异模板和变异功能组合
- 将功能委托/转发给成员(组合)
- 可组合C++功能装饰器
- 具有可变参数模板的功能组合
- Java是否有类似于c ++的组合功能?