创建特征以检测C++中的闭包类型



该标准定义闭包类型如下:

[expr.prim.lambda.closure]lambda-expression的类型(这也是闭包的类型) object) 是唯一的、未命名的非联合类类型,称为闭包 类型,其属性如下所述。[...]

有没有办法创建一个类型特征来检测闭包类型:

template <class T> 
struct is_closure {
static constexpr bool value = /* something */
};
template <class T>
inline constexpr bool is_closure_v = is_closure<T>::value;

如果在纯标准C++中不可行,欢迎在 clang++-5.X 和 g++-7.X 上工作的内联函数。

编辑:使用一些编译器宏获取lambda类型的名称,然后进行一些constexpr字符串处理不是可行的吗?

我很想看看是否真的有一个激励性的用例需要知道,特别是,一个类型是否是闭包。我不确定是否有一个用例来知道,一般来说,一个类型是否可以用一些参数调用 - 而不是专门用一组特定的参数调用。这让我觉得是智力上的手淫。


也就是说,我喜欢智力手淫!闭包类型的好处是它们不可命名。但是我们仍然有像__PRETTY_FUNCTION__这样的钩子,它们给了我们字符串形式的名称,所以它们必须以某种方式可打印—— 并且必须以某种方式与正常名称区分开来。让我们了解如何:

#include <iostream>
template <typename T>
void print(T) {
std::cout << __PRETTY_FUNCTION__ << 'n';
}
namespace N { 
void foo() {
print([]{ return 1; }); 
}
}
int main() {
print([]{ return 1; }); 
print([](auto, auto&&...){ return 2; }); 
N::foo();
}

海湾合作委员会打印:

void print(T) [with T = main()::<lambda()>]
void print(T) [with T = main()::<lambda(auto:1, auto:2&&, ...)>]
void print(T) [with T = N::foo()::<lambda()>]

叮当印花:

void print(T) [T = (lambda at bar.cxx:15:11)]
void print(T) [T = (lambda at bar.cxx:16:11)]
void print(T) [T = (lambda at bar.cxx:10:11)]

在这两种情况下,这些字符串都不能从非闭包类型中产生。我们不能有以<(gcc)开头的类型,也不能有像lambda at(clang)这样的空格的类型。因此,我们可以通过构建一个只寻找适当子字符串的类型特征来利用这一点:

constexpr bool is_equal(const char* a, const char* b) {
for (; *a && *b; ++a, ++b) {
if (*a != *b) return false;
}   
return *b == '';
}
constexpr bool has_substr(const char* haystack, const char* needle) {
for(; *haystack; ++haystack) {
if (is_equal(haystack, needle)) {
return true;
}
}   
return false;
}
template <typename T>
constexpr bool closure_check() {
return has_substr(__PRETTY_FUNCTION__,
#ifdef __clang__
"(lambda at"
#else
"::<lambda"
#endif
);
}
template <typename T>
constexpr bool is_closure_v = closure_check<T>();
template <typename T>
struct is_closure
: std::integral_constant<bool, is_closure_v<T>>
{ };

我还没有彻底测试过,所以我不能自信地说它既没有误报也没有假阴性,但它似乎是正确的方法。

编辑:正如Jarod42指出的那样,这目前还不够,因为它至少没有考虑闭包类型作为模板参数:demo。沿此行可能存在其他误报。


不过,重申一下,我不清楚为什么这样的东西会有用。

最新更新