C++Lambda没有运算符()
C++ Lambda does not have operator()
我需要一种计算函数参数类型的方法,因此我编写了一个closure_traits类,如下所示,灵感来自于是否可以计算lambda的参数类型和返回类型?。
但是,当我尝试将其应用于简单lambda时,我会得到一个错误,即"operator(("不是"(lambda类型("的成员。但是,根据cppreference,lambda确实有一个运算符((。我还尝试使用std::函数,得到了相同的错误。我想我不确定出了什么问题,如果有任何帮助,我们将不胜感激。
#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++14main.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;
您的专业化与decltype(&T::operator())
参数不匹配。
正因为如此,编译器被迫递归地选择相同的主模板,而不是选择专门化(按照您的意愿(。这使得它在已经应用了一次&T::operator()
表达式之后再次应用它。I.e最初尝试执行&T::operator()
实际上成功了,但是当T
已经是int (main()::<lambda(int)>::*)(int) const
时,编译器尝试再次应用&T::operator()
。后者显然没有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
。
编译器正确地获取lambda类型的operator()
,但由于const
限定符,指向该成员函数的指针与您的专业化不匹配。
你应该添加第二个专业化
template <typename ClassType, typename ReturnType,
typename... ArgTypes>
struct closure_traits<ReturnType (ClassType::*) (ArgTypes... args) const>
{
// ...
};
(是的,编写采用函数类型的模板是很痛苦的。(
如果有人对此有问题,正确的代码如下:
#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) const>
{
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::value << std::endl;
return 0;
}
EDIT:评论中(正确地(指出,这不涉及except
说明符和某些cv资格情况。如果你需要的话,你可能需要添加这些案例,或者查看评论中发布的链接。
如果你正在为c++中所有可以调用的类型寻找一个(更(完整的解决方案,那么这些答案中的很多都是有效的,但却错过了一些关键的情况,比如
- 对lambda的引用
- 函数和函数指针
以下是我所知的完整解决方案(如果有任何遗漏,请在评论中告诉我(:
template <typename>
struct closure_traits;
template <typename FunctionT> // overloaded operator () (e.g. std::function)
struct closure_traits
: closure_traits<decltype(&std::remove_reference_t<FunctionT>::operator())>
{
};
template <typename ReturnTypeT, typename... Args> // Free functions
struct closure_traits<ReturnTypeT(Args...)>
{
using arguments = std::tuple<Args...>;
static constexpr std::size_t arity = std::tuple_size<arguments>::value;
template <std::size_t N>
using argument_type = typename std::tuple_element<N, arguments>::type;
using return_type = ReturnTypeT;
};
template <typename ReturnTypeT, typename... Args> // Function pointers
struct closure_traits<ReturnTypeT (*)(Args...)>
: closure_traits<ReturnTypeT(Args...)>
{
};
// member functions
template <typename ReturnTypeT, typename ClassTypeT, typename... Args>
struct closure_traits<ReturnTypeT (ClassTypeT::*)(Args...)>
: closure_traits<ReturnTypeT(Args...)>
{
using class_type = ClassTypeT;
};
// const member functions (and lambda's operator() gets redirected here)
template <typename ReturnTypeT, typename ClassTypeT, typename... Args>
struct closure_traits<ReturnTypeT (ClassTypeT::*)(Args...) const>
: closure_traits<ReturnTypeT (ClassTypeT::*)(Args...)>
{
};
免责声明:std::remove_reference
的灵感来源于此代码。
- 运算符中的不同类型? 具有无捕获,相同的签名,lambda
- 泛型lambda和一元+运算符
- Lambda只是重载了运算符()的类
- lambda 的调用运算符是否需要具有链接?
- C++ lambda 和运算符语法
- 运算符超载的Lambda表达式
- 在命名空间内的 lambda 中使用时未找到运算符重载
- 未定义 Lambda 复制分配运算符
- 初始化在三元运算符中捕获 lambda
- 为什么在三元运算符的分支之间返回 lambda 对某些 lambda 有效?
- C++ lambda 函数中的“运算符=不匹配”错误
- 为什么在重载的 ostream 运算符中引用 lambda 中的向量会导致错误
- const std::function 包装一个非 const 运算符() / 可变 lambda
- 模拟 C++ 中 lambda 的复制赋值运算符
- C++函数斜杠运算符 lambda 表达式
- 如何在提升 lambda 中使用下标运算符
- 使用 lambda 函数定义运算符
- ::运算符 new 是不允许在 lambda 表达式中还是编译器错误?(更新!
- 如何将 lambda 的运算符 () 声明为 noreturn?
- 重载运算符>>用于 lambda