使用带有 lambda 函数指针的模板
Posted
技术标签:
【中文标题】使用带有 lambda 函数指针的模板【英文标题】:Using a template with lambda function pointer 【发布时间】:2020-05-30 11:46:00 【问题描述】:我在玩一些 C++11 功能,遇到了以下问题:
#include <iostream>
#include <vector>
template <class T>
void map(std::vector<T>& values, T(*func)(T))
for (int &value : values)
value = func(value);
int mul2(int x)
return 2*x;
auto mul3 = [](int value)
return value * 3;
;
int main()
std::vector<int> v = 1,2,3,4,5 ;
map(v, mul3);
for (auto value : v)
std::cout << value << std::endl;
使用map
和mul2
可以按预期工作,但是当我使用mul3
函数时,它会出现编译错误。我希望 auto
在这种情况下会给我一个 int 函数指针,但这里似乎不是这种情况。任何人都可以解释这种行为吗?
【问题讨论】:
Lambda 不是函数指针。 @VittorioRomeo 我不明白为什么它不起作用,因为在另一个问题中,OP 问题是捕获,同时在我的 sn-p 中没有捕获 @VittorioRomeo 遗憾的是问题已结束,还有其他选择。您还可以使用“函子”模板模式模板化“函数”。见这里:godbolt.org/z/fdHvAP 我重新打开了这个问题,因为链接的副本是关于捕获 lambdas 而这个问题不是。 “重复”问题的答案没有回答这个问题。 尝试为map
函数明确指定类型T
。 map<int>( v, mul3 );
【参考方案1】:
lambda 可以隐式转换为函数指针,但这不是这里失败的原因。相反,编译器无法推断出T
,因为在推断期间不会发生 lambda 到函数指针的转换。
main.cpp:5:6: note: template argument deduction/substitution failed:
main.cpp:21:16: note: mismatched types 'T (*)(T)' and '<lambda(int)>'
21 | map(v, mul3);
| ^
编译器可以在T(*)(T)
和int(*)(int)
之间建立联系,并且可以在int(*)(int)
和lambda类型之间建立联系,但是它不能在T(*)(T)
和lambda类型之间建立联系。
您可以通过为其建立两个连接之一来解决此问题:显式指定函数的模板参数,或将 lambda 转换为函数指针类型。第一个跳过推导步骤,然后隐式 lambda 到函数指针的转换成功。第二个允许推演成功,因为第二个参数是兼容的函数指针类型。
// Option 1: Specifying T allows implicit conversion of the lambda to fnptr
map<int>(v, mul3);
// Option 2a: Cast of lambda to fnptr allows T to be deduced
map(v, static_cast<int(*)(int)>(mul3));
// Option 2b: Converting lambda to fnptr at mul3 initialization allows T to be deduced
int (*mul3)(int) = [](int value)
return value * 3;
;
但是,我建议以不同的方式解决此问题——函数没有理由必须与向量、函数指针和整数一起使用。为什么它不能与链表、仿函数和双精度对象一起使用?真的没有理由限制这样的类型;就让它们不管它们是什么,看看实例化是否成功:
template <class TContainer, TFunction>
void map(TContainer & values, TFunction const & func)
for (auto &value : values)
value = func(value);
【讨论】:
这是我评论的答案的一个很好的变体 - 但你是如何设法在这里发布答案的? - 我不能/仍然不能这样做(即使它重新打开了?)... @code_fodder 我什至没有看到那个代码,如果我偷了这个问题,我深表歉意。那不是我的意图。我不知道您为什么无法发布答案...我假设您尝试过刷新页面? 啊,别担心,伙计 - 我认为它被锁定,然后解锁,然后锁定,然后再次解锁! - 因为它现在似乎又被解锁了:) ...我会发布我的尝试,你的可能更好更彻底【参考方案2】:根据我的评论扩展(当问题被关闭时),您可以使用仿函数模板“模式”模板化函数详细信息:
template <class T, typename Functor>
void map(std::vector<T>& values, Functor func)
for (int &value : values)
value = func(value);
完整示例请参见此处:https://godbolt.org/z/fdHvAP
【讨论】:
以上是关于使用带有 lambda 函数指针的模板的主要内容,如果未能解决你的问题,请参考以下文章