Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将lambda作为函数指针传递_C++_C++11_Lambda_Function Pointers - Fatal编程技术网

C++ 将lambda作为函数指针传递

C++ 将lambda作为函数指针传递,c++,c++11,lambda,function-pointers,C++,C++11,Lambda,Function Pointers,是否可以将lambda函数作为函数指针传递?如果是这样的话,我一定是做错了什么,因为我得到了一个编译错误 考虑下面的例子 using DecisionFn = bool(*)(); class Decide { public: Decide(DecisionFn dec) : _dec{dec} {} private: DecisionFn _dec; }; int main() { int x = 5; Decide greaterThanThree{ [x

是否可以将lambda函数作为函数指针传递?如果是这样的话,我一定是做错了什么,因为我得到了一个编译错误

考虑下面的例子

using DecisionFn = bool(*)();

class Decide
{
public:
    Decide(DecisionFn dec) : _dec{dec} {}
private:
    DecisionFn _dec;
};

int main()
{
    int x = 5;
    Decide greaterThanThree{ [x](){ return x > 3; } };
    return 0;
}
当输入时,我得到以下编译错误:

函数“int main()”中的
:
17:31:错误:“x”的值在常量表达式中不可用
16:9:注意:“int x”不是常量
17:53:错误:调用'Decise::Decise()'时没有匹配的函数
17:53:注:候选人为:
注:decision::decision(DecisionFn)
9:5:注意:参数1没有从'main()::'到'DecisionFn{aka bool(*)()()}的已知转换
6:7:注意:constexpr decise::decise(const decise&)
6:7:注意:参数1没有从'main()::'到'const decision&'的已知转换
6:7:注意:constexpr decise::decise(decise&&)
6:7:注意:参数1没有从“main()::”到“decision&&”的已知转换

这是一条需要消化的错误消息,但我想我从中得到的是lambda不能被视为
constexpr
,因此我不能将其作为函数指针传递?我也尝试过使
x
常数,但这似乎没有帮助。

lambda只能在没有捕获的情况下转换为函数指针,从
5.1.2
[expr.prim.lambda]一节可以看出(我的重点是):

没有lambda捕获的lambda表达式的闭包类型具有 公共非虚拟非显式常量到指针的转换函数 具有与闭包相同的参数和返回类型的函数 类型的函数调用运算符。此转换返回的值 函数应为调用时具有 与调用闭包类型的函数调用操作符的效果相同

请注意,CPPFREFERENCE在其关于的章节中也介绍了这一点

因此,以下备选方案可行:

typedef bool(*DecisionFn)(int);

Decide greaterThanThree{ []( int x ){ return x > 3; } };
这也会:

typedef bool(*DecisionFn)();

Decide greaterThanThree{ [](){ return true ; } };
正如所指出的,您也可以使用,但请注意,这不是一个成本较低的折衷。

正确地解释了为什么lambda不能作为函数指针传递,如果它有一个捕获。我想展示两个解决这个问题的简单方法

  • 使用
    std::function
    代替原始函数指针。

    这是一个非常干净的解决方案。但是请注意,它包括一些额外的类型擦除开销(可能是一个虚拟函数调用)


  • 正如其他人提到的,可以用Lambda函数代替函数指针。我在C++接口中使用这个方法来解决F77的ODE求解器RKSuff.

    //C interface to Fortran subroutine UT
    extern "C"  void UT(void(*)(double*,double*,double*),double*,double*,double*,
    double*,double*,double*,int*);
    
    // C++ wrapper which calls extern "C" void UT routine
    static  void   rk_ut(void(*)(double*,double*,double*),double*,double*,double*,
    double*,double*,double*,int*);
    
    //  Call of rk_ut with lambda passed instead of function pointer to derivative
    //  routine
    mathlib::RungeKuttaSolver::rk_ut([](double* T,double* Y,double* YP)->void{YP[0]=Y[1]; YP[1]= -Y[0];}, TWANT,T,Y,YP,YMAX,WORK,UFLAG);
    

    Lambda表达式,甚至捕获的表达式,都可以作为函数指针(指向成员函数的指针)处理

    这很棘手,因为lambda表达式不是一个简单的函数。它实际上是一个带有运算符()的对象

    当你有创意的时候,你可以用这个! 设想一个std::function样式的“function”类。 如果保存对象,还可以使用函数指针

    要使用函数指针,可以使用以下命令:

    int first = 5;
    auto lambda = [=](int x, int z) {
        return x + z + first;
    };
    int(decltype(lambda)::*ptr)(int, int)const = &decltype(lambda)::operator();
    std::cout << "test = " << (lambda.*ptr)(2, 3) << std::endl;
    
    int first=5;
    自动lambda=[=](整数x,整数z){
    首先返回x+z+;
    };
    int(decltype(lambda)::*ptr)(int,int)const=&decltype(lambda)::操作符();
    std::cout参数
    模板
    结构lambda_表达式{
    OT_对象;
    RT(OT::*_函数)(A…)常数;
    lambda_表达式(常量和对象)
    :_对象(对象),_函数(&decltype(_对象)::operator()){}
    RT运算符()(A…args)常量{
    返回(_对象。*_函数)(参数…);
    }
    };
    
    使用此功能,您现在可以运行捕获的、未捕获的lambdas,就像您使用原始的:

    auto capture_lambda() {
        int first = 5;
        auto lambda = [=](int x, int z) {
            return x + z + first;
        };
        return lambda_expression<decltype(lambda), int, int, int>(lambda);
    }
    
    auto noncapture_lambda() {
        auto lambda = [](int x, int z) {
            return x + z;
        };
        return lambda_expression<decltype(lambda), int, int, int>(lambda);
    }
    
    void refcapture_lambda() {
        int test;
        auto lambda = [&](int x, int z) {
            test = x + z;
        };
        lambda_expression<decltype(lambda), void, int, int>f(lambda);
        f(2, 3);
    
        std::cout << "test value = " << test << std::endl;
    }
    
    int main(int argc, char **argv) {
        auto f_capture = capture_lambda();
        auto f_noncapture = noncapture_lambda();
    
        std::cout << "main test = " << f_capture(2, 3) << std::endl;
        std::cout << "main test = " << f_noncapture(2, 3) << std::endl;
    
        refcapture_lambda();
    
        system("PAUSE");
        return 0;
    }
    
    auto-capture_lambda(){
    int first=5;
    自动lambda=[=](整数x,整数z){
    首先返回x+z+;
    };
    返回lambda_表达式(lambda);
    }
    自动非捕获λ(){
    自动lambda=[](整数x,整数z){
    返回x+z;
    };
    返回lambda_表达式(lambda);
    }
    void refcapture_lambda(){
    智力测验;
    自动lambda=[&](整数x,整数z){
    试验=x+z;
    };
    lambda_表达式f(lambda);
    f(2,3);
    
    正如前面指出的,捕获lambda不能转换为函数指针

    然而,提供一个指向只接受一个API的函数指针通常是一件非常痛苦的事情。最常被引用的方法是提供一个函数并用它调用一个静态对象

    static Callable callable;
    static bool wrapper()
    {
        return callable();
    }
    
    这很乏味。我们将这一想法进一步推广,并将创建
    包装器的过程自动化,从而使生活更加轻松

    #include<type_traits>
    #include<utility>
    
    template<typename Callable>
    union storage
    {
        storage() {}
        std::decay_t<Callable> callable;
    };
    
    template<int, typename Callable, typename Ret, typename... Args>
    auto fnptr_(Callable&& c, Ret (*)(Args...))
    {
        static bool used = false;
        static storage<Callable> s;
        using type = decltype(s.callable);
    
        if(used)
            s.callable.~type();
        new (&s.callable) type(std::forward<Callable>(c));
        used = true;
    
        return [](Args... args) -> Ret {
            return Ret(s.callable(std::forward<Args>(args)...));
        };
    }
    
    template<typename Fn, int N = 0, typename Callable>
    Fn* fnptr(Callable&& c)
    {
        return fnptr_<N>(std::forward<Callable>(c), (Fn*)nullptr);
    }
    

    由于各种原因,模板方法很聪明,但记住lambda的生命周期和捕获的变量很重要。如果要使用任何形式的lambda指针,并且lambda不是向下的延续,那么只需要复制[=]应使用lambda。即,即使如此,如果捕获的指针(堆栈展开)的生存期短于lambda的生存期,则捕获堆栈上变量的指针也是不安全的

    将lambda捕获为指针的更简单解决方案是:

    auto pLamdba = new std::function<...fn-sig...>([=](...fn-sig...){...});
    
    autoplamdba=newstd::function([=](…fn sig…{…});
    
    e、 例如,
    newstd::function([=]()->void{…}

    只需记住稍后删除pLamdba
    ,以确保不会泄漏lambda内存。
    这里要了解的秘密是,lambda可以捕获lambda(问问你自己这是如何工作的),而且为了使
    std::function
    能够正常工作,lambda实现需要包含足够的内部信息,以提供对lambda(和捕获的)数据大小的访问(这就是为什么删除应该起作用[运行捕获类型的析构函数]。

    使用lambda作为C函数指针的快捷方式如下:

    "auto fun = +[](){}"
    
    使用Curl作为exmample()


    这不是一个直接的答案,而是使用“函子”模板模式来隐藏
    static Callable callable;
    static bool wrapper()
    {
        return callable();
    }
    
    #include<type_traits>
    #include<utility>
    
    template<typename Callable>
    union storage
    {
        storage() {}
        std::decay_t<Callable> callable;
    };
    
    template<int, typename Callable, typename Ret, typename... Args>
    auto fnptr_(Callable&& c, Ret (*)(Args...))
    {
        static bool used = false;
        static storage<Callable> s;
        using type = decltype(s.callable);
    
        if(used)
            s.callable.~type();
        new (&s.callable) type(std::forward<Callable>(c));
        used = true;
    
        return [](Args... args) -> Ret {
            return Ret(s.callable(std::forward<Args>(args)...));
        };
    }
    
    template<typename Fn, int N = 0, typename Callable>
    Fn* fnptr(Callable&& c)
    {
        return fnptr_<N>(std::forward<Callable>(c), (Fn*)nullptr);
    }
    
    void foo(void (*fn)())
    {
        fn();   
    }
    
    int main()
    {
        int i = 42;
        auto fn = fnptr<void()>([i]{std::cout << i;});
        foo(fn);  // compiles!
    }
    
    std::function<void()> func1, func2;
    auto fn1 = fnptr<void(), 1>(func1);
    auto fn2 = fnptr<void(), 2>(func2);  // different function
    
    auto pLamdba = new std::function<...fn-sig...>([=](...fn-sig...){...});
    
    "auto fun = +[](){}"
    
    auto callback = +[](CURL* handle, curl_infotype type, char* data, size_t size, void*){ //add code here :-) };
    curl_easy_setopt(curlHande, CURLOPT_VERBOSE, 1L);
    curl_easy_setopt(curlHande,CURLOPT_DEBUGFUNCTION,callback);
    
    template <typename Functor>
    class Decide
    {
    public:
        Decide(Functor dec) : _dec{dec} {}
    private:
        Functor _dec;
    };
    
    auto decide_fc = [](int x){ return x > 3; };
    Decide<decltype(decide_fc)> greaterThanThree{decide_fc};
    
    int result = _dec(5); // or whatever value
    
    #include <iostream>
    
    
    template<typename Function>
    struct function_traits;
    
    template <typename Ret, typename... Args>
    struct function_traits<Ret(Args...)> {
        typedef Ret(*ptr)(Args...);
    };
    
    template <typename Ret, typename... Args>
    struct function_traits<Ret(*const)(Args...)> : function_traits<Ret(Args...)> {};
    
    template <typename Cls, typename Ret, typename... Args>
    struct function_traits<Ret(Cls::*)(Args...) const> : function_traits<Ret(Args...)> {};
    
    using voidfun = void(*)();
    
    template <typename F>
    voidfun lambda_to_void_function(F lambda) {
        static auto lambda_copy = lambda;
    
        return []() {
            lambda_copy();
        };
    }
    
    // requires C++20
    template <typename F>
    auto lambda_to_pointer(F lambda) -> typename function_traits<decltype(&F::operator())>::ptr {
        static auto lambda_copy = lambda;
        
        return []<typename... Args>(Args... args) {
            return lambda_copy(args...);
        };
    }
    
    
    
    int main() {
        int num;
    
        void(*foo)() = lambda_to_void_function([&num]() {
            num = 1234;
        });
        foo();
        std::cout << num << std::endl; // 1234
    
        int(*bar)(int) = lambda_to_pointer([&](int a) -> int {
            num = a;
            return a;
        });
        std::cout << bar(4321) << std::endl; // 4321
        std::cout << num << std::endl; // 4321
    }