C ++ Lambda没有operator()

时间:2016-11-03 21:06:53

标签: c++ templates lambda functional-programming c++14

我需要一种方法来计算函数的参数类型,所以我写了一个下面给出的closure_traits类,受到Is it possible to figure out the parameter type and return type of a lambda?的启发。

然而,当我尝试将它应用于一个简单的lambda时,我得到的错误是' operator()'不是'(lambda type)'的成员。 但是,根据cppreference,lambda确实有一个operator()。 我也尝试过使用std :: function,并得到了相同的错误。 我想我不确定出了什么问题,任何帮助都会非常感激。

#include<type_traits> 
#include<tuple>                                                                           
#include<utility> 
#include<iostream>                                                                                                     

/* For generic types use the type signature of their operator() */                                                     
template <typename T>                                                                                      
struct closure_traits : public
                        closure_traits<decltype(&T::operator())> {};                                        

/* Otherwise, we do a template match on a function type. */
template <typename ClassType, typename ReturnType, 
          typename... ArgTypes>                                                  
struct closure_traits<ReturnType (ClassType::*) (ArgTypes... args)>                                                  
{
    using arity = std::integral_constant<std::size_t,
                                         sizeof...(ArgTypes)>;                                              
    using Ret = ReturnType;                                  

    /* The argument types will be the same as the types of the 
     * elements of a tuple composed of them. 
     */                                                                                             
    template <std::size_t I>       
    struct Args {        
        using type = typename std::tuple_element<I, 
                                       std::tuple<ArgTypes...>>::type;                                                                                                                     
    };                                                                                                                                                                                                                                        

};                                                                                                                                                                                                                                                

int main() {                                                                                                                     
    auto thing = [=] (int x) {return x;}; 

    std::cerr << "The number of arguments is " 
              << closure_traits<decltype(thing)>::arity << std::endl;                                                                                                                     

    return 0;                                                                                                                       
}    

我得到的编译器错误消息如下。 我的编译命令只是g ++ -std = c ++ 14 main.cpp。

main.cpp: In instantiation of ‘struct closure_traits<int (main()::<lambda(int)>::*)(int) const>’:
main.cpp:9:8:   required from ‘struct closure_traits<main()::<lambda(int)> >’
main.cpp:34:82:   required from here
main.cpp:9:56: error: ‘operator()’ is not a member of ‘int (main()::<lambda(int)>::*)(int) const’
 struct closure_traits : public closure_traits<decltype(&T::operator())> {};                                        
                                                    ^
main.cpp: In function ‘int main()’:
main.cpp:34:51: error: ‘arity’ is not a member of ‘closure_traits<main()::<lambda(int)> >’
 std::cerr << "The number of arguments is " << closure_traits<decltype(thing)>::arity << std::endl; 

3 个答案:

答案 0 :(得分:9)

您的专业化与decltype(&T::operator())参数不匹配。

因此,编译器不是选择专门化(如你所愿),而是强制递归选择相同的主模板。这使得它在已经应用一次之后再次应用&T::operator()表达式。即,&T::operator()的初始尝试实际上是成功的,但是当&T::operator()已经T时,编译器会再次尝试应用int (main()::<lambda(int)>::*)(int) const。显然,后者没有operator (),这就是您收到此错误消息的原因。

无法选择专业化的原因是模板参数声明中缺少const。 lambda的operator ()实际上是lambda类的const成员。将const添加到专业化声明

template <typename ClassType, typename ReturnType, 
          typename... ArgTypes>                                                  
struct closure_traits<ReturnType (ClassType::*) (ArgTypes... args) const>   
...

编译器将遵循您希望它遵循的专门化路径。

当然,您必须打印closure_traits<decltype(thing)>::arity::value,而不仅仅是closure_traits<decltype(thing)>::arity

答案 1 :(得分:4)

编译器正确获取lambda类型的operator(),但由于const限定符,指向该成员函数的指针与您的专业化不匹配。

您应该添加第二个专业化

template <typename ClassType, typename ReturnType, 
          typename... ArgTypes>                                                  
struct closure_traits<ReturnType (ClassType::*) (ArgTypes... args) const>                                                  
{
    // ...
};

(是的,编写模板以获取函数类型很痛苦。)

答案 2 :(得分:1)

如果有人遇到此问题,正确的代码如下:

double