如何拥有指向通用 lambda 的函数指针?

How to have a function pointer to a generic lambda?

正如标题所说,如何用代码表达如下意图?作为函数指针的要求采用任何类型的参数。由于 std::string.

,Variadic 不起作用

https://godbolt.org/z/1E1szT

请注意,我不能直接使用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 = []...;