如何在C 17中定义功能组成
How to define the function composition in c++17?
我想计算函数组成-f(g(param((。这是我尝试的:
auto fComposition(auto&& f, auto&& g, auto&&... params)
{
/* some stuff */
auto result = std::forward<decltype(f)>(f)(
std::forward<decltype(g)>(g)(
std::forward<decltype(params)>(param)
)
);
/* other stuff */
return result;
};
用
编译g++ -std=c++17 src.cpp
基本测试
#include <random>
#include <math.h>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> distr(-1.0, 1.0);
auto xx = fComposition(round, distr, gen);
return 0;
}
我收到的消息是它无法识别第一个功能的类型。
btw,这真的是您的代码吗?您不扩展params
,因此不应编译。
i。定义构图的方式,它与简单的调用是无法区分的:您的fComposition(f, g, arg)
与f(g(arg))
相同,除了额外的字符键入。实际构图通常是一个组合器,它接受两个函数并返回闭合,该闭合在对实际参数进行调用时,将连续应用它们。类似:
template<class F, class G> auto comp(F f, G g) {
return [f, g](auto &&... args) {
return f(g(std::forward<decltype(args)>(args)...));
};
}
(请注意by-values绑定。在C 17中,它们比二十年前更先进。:)您可以通过口味添加std::move
s和 std::forward
s。(
这样,您可以构成两个功能:
auto fg = comp(f, g);
,然后在参数上调用结果:
auto x = fg(arg1, arg2);
ii。但是,真的,为什么要限制两个操作数呢?在Haskell中,(.)
是一个二进制函数。在C 中,我们可以拥有一整棵超载树:
template<class Root, class... Branches> auto comp(Root &&root, Branches &&... branches) {
return [root, branches...](auto &&...args) {
return root(branches(std::forward<decltype(args)>(args)...)...);
};
}
现在,您可以将任何AST封装在一个可召唤中:
int f(int x, int y) { return x + y; }
int g(int x) { return x * 19; }
int h(int x) { return x + 2; }
#include <iostream>
int main() {
auto fgh = comp(f, g, h);
std::cout << fgh(2) << 'n';
}
一种类似的技术是我所知道的唯一在11个标准之前在C 中进行匿名关闭的方式。
iii。但是等等,有图书馆解决方案吗?实际上,是的。来自std::bind
的描述
如果存储的参数arg为t型的
std::is_bind_expression<T>::value == true
(例如,另一个绑定表达式直接传递到初始调用以绑定到绑定(,则绑定函数函数组成:而不是传递函数对象,即绑定子表达会将绑定对象返回,急切地调用子表达,并将其返回值传递给外部调用对象。如果绑定子表达具有任何占位符参数,则将与外部绑定共享(从u1, u2, ...
中挑选(。具体来说,上面的std::invoke
调用中的参数vn
为arg(std::forward<Uj>(uj)...)
,同一调用中的Vn
类型为std::result_of_t<T cv &(Uj&&...)>&&
(CV资格与G的CV级相同(。
对不起,此刻没有例子。> _&lt;
P.S。是的,std::round
是一个超载函数,因此您应该将其输入以指定您需要组合的确切过载。
random
的包含 cmath
,在默认名称空间以及std
名称空间中的libstdc++
中还定义了几个数学运算符(包括round
(。(有关基本原理,请参见此答案。(和C 的round
具有多个过载。结果,您有几个版本的round
可用,并且您的功能不知道要使用哪个round
,因此有关歧义的错误消息。正确的解决方案是消除您的意思是哪个round
。您可以使用静态演员进行此操作:
static_cast<double(*)(double)>(round)
由于您必须经过麻烦,因此您也可以使用cmath
标头代替math.h
并改用std::round
。至少这样您就知道它会超负荷。
- 类模板的成员功能的定义在单独的TU中完全专业化
- C++ - 没有自定义交换功能的移动分配运算符?
- 如何定义可变参数类模板的成员模板功能
- '_HAS_CXX17'宏是否可用于自定义项目标头以启用C++17 语言集功能?
- C++模板功能并定义特定情况
- 这种错误的原因是什么:将"功能"重新定义为不同类型的符号
- 功能原型,没有定义
- 如何在cmake工具链文件中设置编译功能,以便已知的自定义编译器使用target_compile_features
- 如何在C 17中定义功能组成
- 如何自定义功能行为
- 在多态性中重新定义功能(虚拟),具有不同数量的参数
- 定义功能,以便它可以接受列表或向量
- 如何在自定义功能中使用C 构建器OpenArray
- 用户定义功能的返回值的分配:性能
- 使用自己的结构在标题类中定义功能
- 自定义功能不返回正确的值
- 全部使用用户自定义功能和MPI_BOTTOM
- 如何正确定义功能并实现它们
- 重新定义功能
- c++共享库定义和取消定义功能