我需要一种方法来计算函数的参数类型,所以我写了一个下面给出的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;
答案 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