Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;区分lambda和向量中的函数指针_C++_Function_C++11_Lambda - Fatal编程技术网

C++ C++;区分lambda和向量中的函数指针

C++ C++;区分lambda和向量中的函数指针,c++,function,c++11,lambda,C++,Function,C++11,Lambda,我正在编写一个小的事件管理器类,其中我将一些函数指针存储在一个向量中。我使用std::function作为向量类型,我测试了在其中插入lambdas和普通函数,它可以工作: void t(int p){ /*things*/ } [...] event.bind([](int p){/*things*/}); event.bind(t); 现在,(在某一点上,我需要删除lambda,但不需要删除函数),我的问题是: 是否可以区分lambda和函数?如果是,如何进行? 编辑: 既然我澄清了我

我正在编写一个小的事件管理器类,其中我将一些函数指针存储在一个向量中。我使用
std::function
作为向量类型,我测试了在其中插入lambdas和普通函数,它可以工作:

void t(int p){
  /*things*/
}
[...]
event.bind([](int p){/*things*/});
event.bind(t);
现在,(在某一点上,我需要删除lambda,但不需要删除函数),我的问题是:

是否可以区分lambda和函数?如果是,如何进行?

编辑:
既然我澄清了我的疑问,这个问题就变成了标题所说的问题。真正的答案是:你不想这样做。如果你真的想知道原始的类型,不管发生什么情况,它都会破坏类型擦除函子的功能。这闻起来像是糟糕的设计


您可能正在寻找的是。这是一种拉出
函数
对象正在存储的目标函数的基础
类型信息
的方法。每个
类型\u info
都有一个
名称()
,可以按需设置。请注意,这是一个非常深的兔子洞,您基本上需要硬编码各种奇怪的边缘情况。多亏了雅克的大力帮助,我一直在做这件事

不同的编译器对lambda名称的处理方式不同,因此这种方法甚至不具备可移植性。快速检查显示,
clang
抛出一个
$
,而
gcc
抛出
{lambda…#d}
,因此我们可以尝试通过编写以下内容来利用这一点:

bool is_identifier(std::string const& id) {
    return id == "(anonymous namespace)" ||
        (std::all_of(id.begin(), id.end(),
        [](char c){
            return isdigit(c) || isalpha(c) || c == '_';
        }) && !isdigit(id[0]));
}

bool is_lambda(const std::type_info& info)
{
    std::unique_ptr<char, decltype(&std::free)> own {
        abi::__cxa_demangle(info.name(), nullptr, nullptr, nullptr),
        std::free
    };

    std::string name = own ? own.get() : info.name();

    // drop leading namespaces... if they are valid namespace names
    std::size_t idx;
    while ((idx = name.find("::")) != std::string::npos) {
        if (!is_identifier(name.substr(0, idx))) {
            return false;
        }
        else {
            name = name.substr(idx+2);
        }
    }

#if defined(__clang__)
    return name[0] == '$';
#elif defined(__GNUC__)
    return name.find("{lambda") == 0;
#else
    // I dunno?
    return false;
#endif
}
bool是_标识符(std::string const&id){
返回id==(匿名命名空间)||
(std::所有(id.begin()、id.end()、的,
[](字符c){
返回isdigit(c)| | isalpha(c)| | c=='|';
})&&!isdigit(id[0]);
}
布尔是λ(常数标准::类型信息和信息)
{
标准::唯一的{
abi::_cxa_demangle(info.name(),nullptr,nullptr,nullptr),
免费
};
std::string name=own?own.get():info.name();
//删除前导命名空间…如果它们是有效的命名空间名称
标准:尺寸(idx);
while((idx=name.find(“::”)!=std::string::npos){
如果(!是_标识符(name.substr(0,idx))){
返回false;
}
否则{
name=name.substr(idx+2);
}
}
#如果已定义(_u-clang__;)
返回名称[0]='$';
#已定义的elif(_GNUC__)
返回name.find(“{lambda”)==0;
#否则
//我不知道?
返回false;
#恩迪夫
}
然后在你的标准删除习惯用语中加入:

void foo(int ) { }
void bar(int ) { }
long quux(long x) { return x; }

int main()
{
    std::vector<std::function<void(int)>> v;

    v.push_back(foo);
    v.push_back(bar);
    v.push_back(quux);
    v.push_back([](int i) { std::cout << i << '\n';});

    std::cout << v.size() << std::endl; // prints 4

    v.erase(
        std::remove_if(
            v.begin(),
            v.end(),
            [](std::function<void(int)> const& f){
                return is_lambda(f.target_type());
            }),
        v.end()
        );

    std::cout << v.size() << std::endl; // prints 3
}
voidfoo(int){}
空条(int){}
长quux(长x){返回x;}
int main()
{
std::向量v;
v、 推回(foo);
v、 推回(巴);
v、 推回(quux);

v、 push_back([](int i){std::cout注意:此答案假定有有限个不同数量的函数签名可以指定为事件处理程序。它假定使用错误签名分配任何旧函数都是错误的

您可以使用确定哪些是函数指针,并通过消除过程确定哪些必须是lambda:

void func1(int){}
void func2(double){}
int main()
{
向量事件;
事件。推回(功能1);
事件。推回([](int){});
事件。推回(func2);
用于(自动和e:事件)
{
if(如target())

std::cout无论是函数指针还是lambda,它最终都会成为
vector
中的
std::function
。然后
std::function
负责管理函数指针或lambda,而不是您的。这意味着,您只需从
vector
中删除所需的
std::function
。函数的析构函数e> std::function
知道如何正确处理问题。在您的情况下,这意味着不使用函数指针和调用lambdas的析构函数。
std::function
使您能够以一种友好和统一的方式处理不同的事情。不要误用它。

不,不是一般情况

std::function
可以存储指向任何函数的函数指针,该函数可以通过传递单个rvalue
int
来调用。此类签名的数量是无限的

lambda的类型是每个声明的唯一匿名类。两个不同的lambda不共享任何类型关系

您可以确定一个代码> STD::函数< /COD>存储一个特定类型的变量,但是在函数指针和lambda情况下,有一个无限数量的不同类型可以存储在<代码> STD::函数< /代码>中。并且只能测试“完全等于类型”。

您可以访问类型id信息,但那里没有可移植的表示,通常将该信息用于身份匹配(和相关)或调试之外的任何事情都是一个坏主意


现在,这个问题的限制版本(你能告诉我一个
std::function
是否包含一个
void(*)(int)
)类型的函数指针)很容易解决。但总的来说,这样做仍然是个坏主意:首先,因为它很微妙(代码远离您使用它的地方,就像对函数签名的细微更改一样,可能会破坏一些东西),其次,根据存储在
std::function
中的类型检查和更改您的行为只应在极端情况下进行(通常涉及将代码从使用
void*
style回调更新为
std::function
style回调).

什么意思,删除lambda?为什么lambda被视为不同于函数指针?您的设计看起来…错误。您可以将带有
bool
std::pair
作为第二个参数,而
bool
将指示它是函数指针还是lambda。如果您想区分ambda和函数指针,不要把它们放在一个向量中,以同样的方式对待它们…(P
void func1(int) {}
void func2(double) {}

int main()
{

    std::vector<std::function<void(int)>> events;

    events.push_back(func1);
    events.push_back([](int){});
    events.push_back(func2);

    for(auto& e: events)
    {
        if(e.target<void(*)(int)>())
            std::cout << "funcion int" << '\n';
        else if(e.target<void(*)(double)>())
            std::cout << "funcion double" << '\n';
        else
            std::cout << "must be lambda" << '\n';
    }
}
void func(int) {}

int main()
{

    std::function<void(int)> f = func;

    if(f.target<void(*)(int)>())
        std::cout << "not a lambda" << '\n';
}