创建一个特征来检测C++中的闭包类型

Vin*_*ent 2 c++ lambda type-traits template-meta-programming c++17

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

[expr.prim.lambda.closure] lambda表达式的类型(也是闭包对象的类型)是一个唯一的,未命名的非联合类类型,称为闭包类型,其属性如下所述.[...]

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

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

template <class T>
inline constexpr bool is_closure_v = is_closure<T>::value;
Run Code Online (Sandbox Code Playgroud)

如果在纯粹的标准C++中不可行,那么欢迎使用clang ++ - 5.X和g ++ - 7.X的内部函数.

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

Bar*_*rry 6

我很想看看是否真的有一个激励性的用例需要知道,特别是一个类型是否是一个闭包.我不确定是否有一个用例来知道一般来说一个类型是否可以用一些参数调用- 而不是特别是可以用它们的特定集合进行调用.这种打击我作为智力手淫.


那说,我喜欢智力手淫!闭包类型的好处是它们不可名.但是我们仍然有类似的钩子__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();
}
Run Code Online (Sandbox Code Playgroud)

gcc打印:

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()>]
Run Code Online (Sandbox Code Playgroud)

铿锵声:

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)]
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,这些字符串都不能从非闭包类型生成.我们不能有以<(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 == '\0';
}

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>>
{ };
Run Code Online (Sandbox Code Playgroud)

我没有对此进行彻底的测试,所以我不能自信地说它既没有误报也没有否定,但这似乎是正确的方法.

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


虽然,重申一下,我不清楚为什么这样的事情会有用.