我正在尝试创建一个通用的包装器函数,它将函数作为模板参数,并使用与该函数相同的参数作为其参数.例如:
template <typename F, F func>
/* return type of F */ wrapper(Ts... Args /* not sure how to get Ts*/)
{
// do stuff
auto ret = F(std::forward<Ts>(args)...);
// do some other stuff
return ret;
}
Run Code Online (Sandbox Code Playgroud)
解决方案需要可以转换为具有相同类型的函数指针,func以便我可以将其传递给C api.换句话说,解决方案需要是一个函数而不是一个函数对象.最重要的是,我需要能够在包装函数中完成工作.
如果内联评论不清楚,我希望能够做如下的事情:
struct c_api_interface {
int (*func_a)(int, int);
int (*func_b)(char, char, char);
};
int foo(int a, int b)
{
return a + b;
}
int bar(char a, char b, char c)
{
return a + b * c; …Run Code Online (Sandbox Code Playgroud) 假设我想要一个C++函数对两个输入执行算术运算,将它们视为给定类型:
伪:
function(var X,var Y,function OP)
{
if(something)
return OP<int>(X,Y);
else if(something else)
return OP<double>(X,Y);
else
return OP<string>(X,Y);
}
Run Code Online (Sandbox Code Playgroud)
适合OP的函数可能如下:
template <class T> add(var X,var Y)
{
return (T)X + (T)Y; //X, Y are of a type with overloaded operators
}
Run Code Online (Sandbox Code Playgroud)
那么,问题是函数的签名是什么样的?如果操作符函数是非模板化的,我可以做到,但我对这种额外的复杂性感到困惑.
std::transform来自<algorithm>标题的内容适用于范围,它“使”我们能够使用范围作为它们本身的函子(在范畴论的意义上(\xc2\xb9))。std::transform是基于迭代器的,是的,但std::ranges::views::transform不是,并且它的签名与函数语言中相应函数的签名密切匹配(对两个参数的不同顺序取模,但这没什么大不了的)。
当我看到这个问题(以及在回答它的过程中)时,我了解到 C++23 引入了std::optional<T>::transform,它std::optional也创建了一个函子。
所有这些消息确实让我兴奋,但我不禁想到函子是通用的,如果有一个统一的接口就好了transform任何函子都有一个统一的接口会很好,例如 Haskell 中的情况。
这让我认为类似的对象std::ranges::views::transform(具有不同的名称,而不是暗示ranges)可以成为一个定制点,STL不仅可以为范围定制,还可以为std::optionalSTL中的任何其他函子定制,而程序员可以为其用户定义的类定制它。
非常相似,C++23 也引入了std::optional<T>::and_then,它基本上是 的一元绑定std::optional。我不知道有任何类似的函数可以实现范围的单子绑定,但 C++20本质上是withsome_range | std::ranges::views::transform(f) | std::ranges::views::join的单子绑定。some_rangef
这让我认为可能存在一些通用接口,命名它mbind,人们可以选择使用任何类型。例如,STL 将选择std::optional通过按照 来实现它。std::optional<T>::and_then
该语言是否有机会或有计划有一天支持这种通用性?
\n我当然可以看到一些问题。今天 不完全是,破坏依赖于基于 SFINAE 的无效代码检测的代码是可以的。std::ranges::views::transform(some_optional, some_func)无效,因此某些代码可能依赖于 SFINAE。让它突然工作会破坏代码。
(\xc2\xb9) 关于 …
我最近对仿函数很兴奋,并且一直在使用它们.然后情况出现了,我需要我的仿函数执行两个不同的操作,我想到为我的仿函数添加另一个方法(不重载()运算符).这是不是不好的做法我不确定(也许你可以告诉我),但它让我思考为什么我首先使用仿函数而不仅仅是对象.所以我的问题是:
有没有什么特别的重载()运算符或者它是否比使用普通的命名方法更具语法吸引力?
更新:
首先,我知道为什么函子可能比其他问题中解释的函数指针更可取.我想知道为什么它们可以优于具有命名方法的对象.
其次,至于我何时想要使用另一个可能命名的函子方法的例子:基本上我有两个函数,一个计算一个叫做图形分区的模块性的东西compute_modularity(),另一个用于计算一些变化后的模块化增益分区compute_modularity_gain().我以为我可以将这些函数作为同一仿函数的一部分传递给优化算法,并将增益作为命名函数.我不只是传递了两个函子到算法,其原因是,我想执行这一compute_modularity_gain()只与使用一起选择compute_modularity(),而不是另一个函子如compute_stability()(应该仅被使用compute_stability_gain().换句话说,增益功能必须紧密加上它的兄弟功能.如果还有其他方法我可以执行这个约束,那么请告诉我.
我试图使用本地类作为函子并使用g ++(3.4.6)获得编译器错误.
将下面的class(Processor)放在全局范围内可以解决错误,所以我猜错误是因为函数本地结构/类.我更喜欢在函数内部使用类,以实现代码清晰度和易用性.想知道是否有解决方法使下面的代码有效.
test.cpp:24:错误:没有匹配函数来调用\ u2018foreachArg(int&,char*&,processSubs(int,char*):: Processor&)\ u2019
template <class Functor>
void foreachArg(int n, char *args[], Functor& f)
{
for(int i=0; i<n; ++i)
f(args[i]);
}
int processSubs(int argc, char *args[])
{
class Processor
{
public:
void operator()(const char *arg)
{
}
};
Processor p;
foreachArg(argc, args, p);
}
int main(int argc, char *argv[])
{
processSubs(argc, argv);
}
Run Code Online (Sandbox Code Playgroud) 作为一个愚蠢的例子,假设我有一个函数int f(vector<int> v),由于某种原因,我需要v多次执行几个操作f.而不是在其他地方放置辅助函数(这可能会增加混乱并损害可读性),做这样的事情有哪些优点和缺点(效率,可读性,可维护性等):
int f(vector<int> v)
{
auto make_unique = [](vector<int> &v)
{
sort(begin(v), end(v));
auto unique_end = unique(begin(v), end(v));
v.erase(unique_end, end(v));
};
auto print_vector = [](vector<int> const &v)
{
copy(begin(v), end(v), ostream_iterator<int>(cout, " "));
cout << endl;
};
make_unique (v);
print_vector(v);
// And then the function uses these helpers a few more times to justify making
// functions...
}
Run Code Online (Sandbox Code Playgroud)
还是有一些首选的选择?
此代码有效:
#include <iostream>
#include <queue>
#include <vector>
#include <functional>
using namespace std;
int main(){
priority_queue<int,vector<int>,greater<int> > pq;
pq.push(1);
cout<<pq.top()<<endl;
}
Run Code Online (Sandbox Code Playgroud)
但是,此代码无法编译:
#include <iostream>
#include <queue>
#include <vector>
#include <functional>
using namespace std;
int main(){
priority_queue<int,vector<int>,greater<int>() > pq;
pq.push(1);
cout<<pq.top()<<endl;
}
Run Code Online (Sandbox Code Playgroud)
为什么?
我所了解的是,它greater<int>() 是一个函数对象,并且priority_queue接受二进制谓词作为第三个参数,并且谓词是一种特殊的函子类型。但是这对大括号如何使这一点有所不同。
sum(2)(3);?并提到其他常规相当于这个电话?可以像下面的代码一样创建此调用的sum函数
function sum(x) {
if (arguments.length == 2) {
return arguments[0] + arguments[1];
} else {
return function(y) { return x + y; };
}
}
console.log(sum(2,3)); // Outputs 5
console.log(sum(2)(3)); // Outputs 5Run Code Online (Sandbox Code Playgroud)
我最近开始研究lambdas供个人使用.我已经编写了几年了,我已经发布了多种产品,但是,我从未发现自己需要使用lambdas.我已经阅读了各种lambda问题的其他堆栈交换答案,但是我没有找到一个解释,它显示了一个非常简单的例子,它真正推动了lambdas是必要的(在某些情况下).在做了一些研究之后,我不相信lambdas的某些特定用法不能用标准函数实现,但是,这并不意味着太多,因为我的主题范围非常有限.
有人可以为lambda提供一个相当简单的用例,演示它们如何比典型函数更强大(在正确的情况下)?
我使用struct minHeap使用priority_queue生成最小堆.并使用函数comp以相反的顺序使用STL中给出的sort函数打印数字.现在我的疑问是我不能在函数排序中使用struct minHeap而不能在priorityQueue中使用函数comp.
我觉得struct minHeap和comp的功能是相似的.请解释我何时使用comaprator的结构以及何时使用普通函数在STL中作为比较器?
#include<iostream>
#include <queue>
#include <stdio.h>
#include<algorithm>
using namespace std;
struct minHeap
{
bool operator()(const int a , const int b )
{
return a>b;
}
};
bool comp(int a , int b)
{
return a>b;
}
int main()
{
priority_queue<int , vector<int> , minHeap > b;
b.push(4);
b.push(23);
b.push(12);
while(b.size()!=0)
{
cout << b.top() << " " ;
b.pop();
}
cout<<"\n" ;
int arr[] = {12,34, 112,12};
sort(arr , arr+4 ,comp);
for(int x= 0 ; …Run Code Online (Sandbox Code Playgroud) c++ ×9
functor ×3
templates ×3
c++11 ×2
lambda ×2
c++23 ×1
coding-style ×1
comparator ×1
ecmascript-6 ×1
html ×1
javascript ×1
jquery ×1
monads ×1
predicate ×1
stl ×1
web ×1