如何拥有指向通用 lambda 的函数指针?
How to have a function pointer to a generic lambda?
正如标题所说,如何用代码表达如下意图?作为函数指针的要求采用任何类型的参数。由于 std::string
.
,Variadic 不起作用
请注意,我不能直接使用auto fp = <the lambda>
,因为fp
是一个class成员变量。
#include <iostream>
template<typename T1, typename T2>
void(*fp)(T1 t1, T2 t2) = [](auto a, auto b){
std::cout << a << "--"
<< b << std::endl;
};
int main(){
fp(1, 2);
fp('a', 'b');
}
你不能有这样的模板函数指针,但请记住,lambda 只是语法糖,你可以自己编写 class。
class fp {
template<class AT, class BT>
void operator()(AT&& a, BT&& b) {
std::cout << a << "--" << b << std::endl;
};
};
class class_with_functionoid_member {
fp fn_;
};
更通用的版本是您可以将 lambda 作为成员。您必须将 lambda 类型作为 class 参数。
template<class fnT>
class class_with_lambda_member {
fnT fn_;
public:
class_with_lambda_member(fnT fn) : fn_(std::move(fn)) {}
};
要点是函数指针是一种运行时类型擦除,模板成员函数需要编译时懒实例化,C++没办法把这两个概念混在一起。我想到的所有解决方法都围绕着在“接口”中明确列出 T1 和 T2` 的所有可能组合,它不与函数指针混合,但可以与函数指针查找对象一起使用。
struct erasable_functions {
virtual ~erasable_functions(){}
virtual void operator()(int, int)=0;
virtual void operator()(int, char)=0;
virtual void operator()(char, int)=0;
virtual void operator()(char, char)=0;
};
template<class lambdaT>
struct erased_functions : erasable_functions {
lambdaT lambda_;
erased_functions(lambdaT lambda) : lambda_(std::move(lambda)){}
virtual void operator()(int a, int b) {lambda_(a, b);
virtual void operator()(int a, char b) {lambda_(a, b);
virtual void operator()(char a, int b) {lambda_(a, b);
virtual void operator()(char a, char b) {lambda_(a, b);
};
template<class lambdaT>
erased_functions<lambdaT> erase_functions(lambdaT lambda)
{return {std::move(lambda)};}
struct class_with_functionoid_member {
erasable_functions* functions_;
class_with_functionoid_member(erasable_functions* functions) : functions_(functions){}
void operator()(int a, int b) {(*functions_)(a, b);
void operator()(int a, char b) {(*functions_)(a, b);
void operator()(char a, int b) {(*functions_)(a, b);
void operator()(char a, char b) {(*functions_)(a, b);
};
int main() {
auto lambda = erase_functions([](auto a, auto b) {
std::cout << a << "--" << b << std::endl;
};
class_with_functionoid_member c(&lambda);
}
变量模板非常好。
即使你初始化它们的方式也很好。
请注意它是变量的模板,而不是存储模板的变量(模板不存在)。
因此,当最终使用它时,一切都崩溃了:
编译器如何知道您指的是无数潜在实例中的哪一个?
很简单,你必须 actually tell it:
int main(){
fp<int, int>(1, 2);
fp<char, char>('a', 'b');
}
当然,手动对 lambda 进行脱糖并获取它的实例 would be more practical:
struct {
template <class T1, class T2>
void operator()(T1 a, T2 b) const {
std::cout << a << "--" << b << std::endl;
};
} fp;
遗憾的是,我们不能简单地给 lambda 一个名字,然后让编译器来计算它。
为合适的语法集思广益候选人:
struct A = []...;
struct B : []... {
};
using C = []...;
正如标题所说,如何用代码表达如下意图?作为函数指针的要求采用任何类型的参数。由于 std::string
.
请注意,我不能直接使用auto fp = <the lambda>
,因为fp
是一个class成员变量。
#include <iostream>
template<typename T1, typename T2>
void(*fp)(T1 t1, T2 t2) = [](auto a, auto b){
std::cout << a << "--"
<< b << std::endl;
};
int main(){
fp(1, 2);
fp('a', 'b');
}
你不能有这样的模板函数指针,但请记住,lambda 只是语法糖,你可以自己编写 class。
class fp {
template<class AT, class BT>
void operator()(AT&& a, BT&& b) {
std::cout << a << "--" << b << std::endl;
};
};
class class_with_functionoid_member {
fp fn_;
};
更通用的版本是您可以将 lambda 作为成员。您必须将 lambda 类型作为 class 参数。
template<class fnT>
class class_with_lambda_member {
fnT fn_;
public:
class_with_lambda_member(fnT fn) : fn_(std::move(fn)) {}
};
要点是函数指针是一种运行时类型擦除,模板成员函数需要编译时懒实例化,C++没办法把这两个概念混在一起。我想到的所有解决方法都围绕着在“接口”中明确列出 T1 和 T2` 的所有可能组合,它不与函数指针混合,但可以与函数指针查找对象一起使用。
struct erasable_functions {
virtual ~erasable_functions(){}
virtual void operator()(int, int)=0;
virtual void operator()(int, char)=0;
virtual void operator()(char, int)=0;
virtual void operator()(char, char)=0;
};
template<class lambdaT>
struct erased_functions : erasable_functions {
lambdaT lambda_;
erased_functions(lambdaT lambda) : lambda_(std::move(lambda)){}
virtual void operator()(int a, int b) {lambda_(a, b);
virtual void operator()(int a, char b) {lambda_(a, b);
virtual void operator()(char a, int b) {lambda_(a, b);
virtual void operator()(char a, char b) {lambda_(a, b);
};
template<class lambdaT>
erased_functions<lambdaT> erase_functions(lambdaT lambda)
{return {std::move(lambda)};}
struct class_with_functionoid_member {
erasable_functions* functions_;
class_with_functionoid_member(erasable_functions* functions) : functions_(functions){}
void operator()(int a, int b) {(*functions_)(a, b);
void operator()(int a, char b) {(*functions_)(a, b);
void operator()(char a, int b) {(*functions_)(a, b);
void operator()(char a, char b) {(*functions_)(a, b);
};
int main() {
auto lambda = erase_functions([](auto a, auto b) {
std::cout << a << "--" << b << std::endl;
};
class_with_functionoid_member c(&lambda);
}
变量模板非常好。
即使你初始化它们的方式也很好。
请注意它是变量的模板,而不是存储模板的变量(模板不存在)。
因此,当最终使用它时,一切都崩溃了:
编译器如何知道您指的是无数潜在实例中的哪一个?
很简单,你必须 actually tell it:
int main(){
fp<int, int>(1, 2);
fp<char, char>('a', 'b');
}
当然,手动对 lambda 进行脱糖并获取它的实例 would be more practical:
struct {
template <class T1, class T2>
void operator()(T1 a, T2 b) const {
std::cout << a << "--" << b << std::endl;
};
} fp;
遗憾的是,我们不能简单地给 lambda 一个名字,然后让编译器来计算它。
为合适的语法集思广益候选人:
struct A = []...;
struct B : []... {
};
using C = []...;