what is the type signature of a c++11/1y lambda function?

后端 未结 4 1733
心在旅途
心在旅途 2020-12-05 11:09

I was wondering if there is a standard way to get the type signature (i.e. the return type and the types) of its parameters of any given lambda?

The reason I ask is

4条回答
  •  温柔的废话
    2020-12-05 11:44

    According to Can the 'type' of a lambda expression be expressed?, there is actually a simple way in current c++ (without needing c++1y) to figure out the return_type and parameter types of a lambda. Adapting this, it is not difficult to assemble a std::function typed signature type (called f_type below) for each lambda.

    I. With this abstract type, it is actually possible to have an alternative way to auto for expressing the type signature of a lambda, namely function_traits<..>::f_type below. Note: the f_type is not the real type of a lambda, but rather a summary of a lambda's type signature in functional terms. It is however, probably more useful than the real type of a lambda because every single lambda is its own type.

    As shown in the code below, just like one can use vector::iterator_type i = v.begin(), one can also do function_traits::f_type f = lambda, which is an alternative to the mysterious auto. Of course, this similarity is only formal. The code below involves converting the lambda to a std::function with the cost of type erasure on construction of std::function object and a small cost for making indirect call through the std::function object. But these implementation issues for using std::function aside (which I don't believe are fundamental and should stand forever), it is possible, after all, to explicitly express the (abstract) type signature of any given lambda.

    II. It is also possible to write a make_function wrapper (pretty much like std::make_pair and std::make_tuple) to automatically convert a lambda f ( and other callables like function pointers/functors) to std::function, with the same type-deduction capabilities.

    Test code is below:

    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    // For generic types that are functors, delegate to its 'operator()'
    template 
    struct function_traits
        : public function_traits
    {};
    
    // for pointers to member function
    template 
    struct function_traits {
        //enum { arity = sizeof...(Args) };
        typedef function f_type;
    };
    
    // for pointers to member function
    template 
    struct function_traits {
        typedef function f_type;
    };
    
    // for function pointers
    template 
    struct function_traits  {
      typedef function f_type;
    };
    
    template  
    typename function_traits::f_type make_function(L l){
      return (typename function_traits::f_type)(l);
    }
    
    long times10(int i) { return long(i*10); }
    
    struct X {
      double operator () (float f, double d) { return d*f; } 
    };
    
    // test code
    int main()
    {
        auto lambda = [](int i) { return long(i*10); };
        typedef function_traits traits;
        traits::f_type ff = lambda;
    
        cout << make_function([](int i) { return long(i*10); })(2) << ", " << make_function(times10)(2) << ", " << ff(2) << endl;
        cout << make_function(X{})(2,3.0) << endl;
    
        return 0;
    }
    

提交回复
热议问题