gpt4 book ai didi

c++ - 二进制通用 lambda 不匹配 ptr-to-function 参数?

转载 作者:搜寻专家 更新时间:2023-10-31 00:59:59 24 4
gpt4 key购买 nike

从这些 SE 问题中,Passing lambda as function pointer , Lambda as function parameter , Cannot pass lambda function as function reference? ,我了解到我可以将无状态、非捕获的 lambda 传递给需要函数指针的函数。因此,我尝试了一个模板来提升类型 T (*bf)(T, T) over std::vectors 的二元函数:

template<typename T>
vector <T> lift_binary (const vector<T> & v1, const vector<T> & v2,
T (* bf)(T, T))
{ auto result = vector<T> ();
result.resize(v1.size());
transform (v1.begin(), v1.end(), v2.begin(), result.begin(), bf);
return result; }

这适用于 bf 是一个命名函数,例如

template<typename T> T minus (T x, T y) { return x - y; }

template<typename T>
vector<T> operator- (const vector<T> &v1, const vector<T> &v2)
{ return lift_binary (v1, v2, minus); }

int main()
{ auto v1 = vector<double> ({1, 2, 3});
auto v2 = vector<double> ({10, 20, 30});
auto v3 = v1 - v2;
cout << v3[0] << " " << v3[1] << " " < v3[2] << " " << endl;
return 0; }

产生

-9 -18 -27

但它不适用于以下三个 lambda 函数中的任何一个(例如,第二个函数未注释):

template<typename T>
vector<T> operator- (const vector<T> &v1, const vector<T> &v2)
// { return lift_binary (v1, v2, [] (T x, T y) -> T { return x - y; } ); }
{ return lift_binary (v1, v2, [] (T x, T y) { return x - y; } ); }
// { return lift_binary (v1, v2, [] (auto x, auto y) { return x - y; } ); }
// { return lift_binary (v1, v2, minus); }

这样编译的时候

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

编译器无法将参数类型 T (*bf)(T, T) 与 lambda 的类型相匹配:

main.cpp: In instantiation of 'std::vector<_RealType> operator-(const std::vector<_RealType>&, const std::vector<_RealType>&) [with T = double]':
main.cpp:37:20: required from here
main.cpp:26:31: error: no matching function for call to 'lift_binary(const std::vector<double>&, const std::vector<double>&, operator-(const std::vector<_RealType>&, const std::vector<_RealType>&) [with T = double]::<lambda(double, double)>)'
{ return lift_binary (v1, v2, [] (T x, T y) { return x - y; } ); }
^
main.cpp:13:16: note: candidate: template<class T> std::vector<_RealType> lift_binary(const std::vector<_RealType>&, const std::vector<_RealType>&, T (*)(T, T))
vector <T> lift_binary (const vector<T> & v1, const vector<T> & v2, T (* bf)(T, T))
^
main.cpp:13:16: note: template argument deduction/substitution failed:
main.cpp:26:31: note: mismatched types 'T (*)(T, T)' and 'operator-(const std::vector<_RealType>&, const std::vector<_RealType>&) [with T = double]::<lambda(double, double)>'
{ return lift_binary (v1, v2, [] (T x, T y) { return x - y; } ); }

我在其他两个 lambda 表达式中得到了类似的错误。这使我认为没有一种通用的 lambda 会匹配参数的函数指针类型,但这与我能够找到和阅读的内容不符。我一定是做错了什么。

这是一个在线示例的 coliru 项目:

http://coliru.stacked-crooked.com/a/77756b84eb401156

这是 block 中的整个代码片段:

#include<iostream>
#include<vector>
#include<algorithm>

using std::cout;
using std::endl;
using std::vector;

template<typename T>
vector <T> lift_binary (const vector<T> & v1, const vector<T> & v2, T (* bf)(T, T))
{ auto result = vector<T> ();
result.resize(v1.size());
transform (v1.begin(), v1.end(), v2.begin(), result.begin(), bf);
return result; }

template<typename T>
T minus (T x, T y)
{ return x - y; }

template<typename T>
vector<T> operator- (const vector<T> &v1, const vector<T> &v2)
// { return lift_binary (v1, v2, [] (T x, T y) -> T { return x - y; } ); }
{ return lift_binary (v1, v2, [] (T x, T y) { return x - y; } ); }
// { return lift_binary (v1, v2, [] (auto x, auto y) { return x - y; } ); }
// { return lift_binary (v1, v2, minus); }

template<typename T>
vector<T> operator+(const vector<T> & v1, const vector<T> & v2)
{ return lift_binary (v1, v2, [] (T x, T y) -> T { return x + y; } ); }

int main()
{ auto v1 = vector<double> ({1, 2, 3});
auto v2 = vector<double> ({10, 20, 30});
auto v3 = v1 - v2;
cout << v3[0] << " "
<< v3[1] << " "
<< v3[2] << " " << endl;
return 0; }

编辑:

以下作品:

template<typename T>
vector<T> operator- (const vector<T> &v1, const vector<T> &v2)
{ auto result = vector<T> ();
result.resize(v1.size());
transform (v1.begin(), v1.end(), v2.begin(), result.begin(),
[] (T x, T y) { return x - y; } );
return result; }

原始问题的全部动机只是让我对这种模式进行抽象,以便在实现其他二元运算符(如 + , *

我希望能够通过编写一个将 T(*)(T,T) 作为参数的高阶函数 lift_binary 来抽象出 lambda 表达式参数,因为我认为这是 lambda 的类型。

最佳答案

由于 minus 是一个函数模板,编译器在用作参数 T 的函数调用中的参数时不会尝试基于它推导类型 T(*bf)(T,T),因为它是非推导上下文之一:

§ 14.8.2.5 [temp.deduct.type]/p5:

The non-deduced contexts are:

(5.5) — A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions (13.4), and one or more of the following apply:

(5.5.1) — more than one function matches the function parameter type (resulting in an ambiguous deduction), or

(5.5.2) — no function matches the function parameter type, or

(5.5.3)the set of functions supplied as an argument contains one or more function templates.

因此,类型 T 是根据第一个和第二个参数( vector )推导出来的,然后用于定义函数指针类型本身。这就是它适用于普通 函数的原因。


I expected to be able to abstract out the lambda expression by writing a higher-order function lift_binary that takes a T(*)(T,T) as a parameter because I thought that's the type of the lambda.

lambda 有一些实现定义的和唯一的类型。转换为函数指针是可能的,因为 lambda 的类型为此目的定义了一个转换运算符。但是,编译器不会将 lambda 表达式视为一组重载函数,并会尝试根据您作为 T 的参数传递的内容来推断类型 T(*bf)(T,T) 。显然,这注定会失败,因为 lambda 的(类)类型无法与函数指针类型匹配。

要解决这个问题,您可以自己为该参数不可推导制作 T(这称为 identity trick ):

template <typename T> struct identity { using type = T; };
template <typename T> using identity_t = typename identity<T>::type;

template<typename T>
vector<T> lift_binary (const vector<T> & v1
, const vector<T> & v2
, identity_t<T(T,T)>* bf);
// ~~~~~~~~~~~~~~~~~~^

// ...

lift_binary(v1, v2, [] (auto x, auto y) { return x - y; } );

DEMO

对于非泛型 lambda,您可以使用一元加号运算符强制将其转换为指向调用点函数的指针:

lift_binary(v1, v2, +[] (T x, T y) { return x - y; });
// ^

DEMO 2

或者明确地转换一个通用的 lambda,(也在调用站点),以便它可以匹配 T(*)(T,T) :

lift_binary(v1, v2, static_cast<T(*)(T,T)>([] (auto x, auto y) { return x - y; }));
// ~~~~~~~~~~~~~~~~~~~~~^

DEMO 3

...或者,由于 T 已经在 operator- 中推导出来,您可以将其传递到模板参数列表中:

return lift_binary<T>(v1, v2, [] (auto x, auto y) { return x - y; } );
// ~~^

旁注:您始终可以按如下方式声明 lift_binary 函数:

template <typename T, typename F>     
auto lift_binary(const vector<T>& v1, const vector<T>& v2, F bf)

关于c++ - 二进制通用 lambda 不匹配 ptr-to-function 参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32188099/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com