c++将Lambdas与vector中的Function指针区分开来
C++ distinguish Lambdas from Function pointers inside a vector
我正在编写一个小事件管理器类,我在向量中存储一些函数指针。我使用std::function<void(int)>
作为向量类型,我测试了在它内部插入lambda和正常函数,它工作:
void t(int p){
/*things*/
}
[...]
event.bind([](int p){/*things*/});
event.bind(t);
现在,(在某一点上我需要删除lambdas而不是函数,)我的问题是:
是否有可能从函数中区分lambdas ?如果是,怎么做?
编辑:
既然我澄清了我的疑问,这个问题就变成了标题所说的
真正的答案是:你不想这样做。如果你想知道在任何情况下的原始类型,它就违背了类型消除函子的意义。这就像糟糕的设计。
你可能要找的是std::function::target_type
。这是一种提取function
对象存储的目标函数的底层type_info
的方法。每个type_info
都有一个name()
,它可以被拆卸。请注意,这是一个非常深的兔子洞,你基本上必须硬编码各种奇怪的边缘情况。就像我一直在做的一样,感谢牦牛的热心帮助。
不同的编译器会以不同的方式处理它们的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
}
然后把它放到标准的擦除习惯用法中:
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
}
不,一般不。
std::function<void(int)>
可以存储一个函数指针,该指针指向任何可以通过传递一个右值int
调用的函数。有无数个这样的签名。
lambda的类型是每个声明的唯一匿名类。两个不同的lambda不共享任何类型关系。
您可以确定std::function<void(int)>
是否存储特定类型的变量,但是在函数指针和lambda的情况下,可以考虑在std::function
中存储的不同类型的数量是无限的。你只能测试"完全等于一个类型"。
您可以访问类型id信息,但那里没有可移植的表示,并且通常将该信息用于标识匹配(及相关)或调试以外的任何事情都是坏主意。
现在,这个问题的限制版本(你能告诉std::function<void(int)>
是否包含void(*)(int)
类型的函数指针)很容易解决。但总的来说,这样做仍然是一个坏主意:首先,因为它很微妙(代码远离你使用它的地方,就像对函数签名的细微改变,可能会破坏东西),其次,根据存储在std::function
中的类型检查和改变你的行为应该只在极端的极端情况下完成(通常涉及更新你的代码从使用void*
风格回调到std::function
风格回调)。
无论是函数指针还是lambda,它最终作为vector
中的std::function<void(int)>
。然后std::function<void(int)>
负责管理函数指针或lambda,而不是您的。这意味着,您只需从vector
中删除您想要的std::function<void(int)>
。std::function<void(int)>
的析构函数知道如何做正确的事情。在您的情况下,这将对函数指针不做任何事情,并调用lambda的析构函数。std::function<void(int)>
使您能够以一种友好和统一的方式对待不同的事物。别误用了
注意:这个答案的前提是存在一个有限的、不同数量的函数签名可以被分配为事件处理程序。它假定用错误的签名赋值任何旧函数都是错误的。
您可以使用std::function::target确定哪些是函数指针,并通过消去过程确定哪些必须是lambdas:
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';
}
}
这可以工作,因为如果形参类型不匹配,std::function::target返回空指针。
单变量示例:
void func(int) {}
int main()
{
std::function<void(int)> f = func;
if(f.target<void(*)(int)>())
std::cout << "not a lambda" << 'n';
}
- 如何将函数指针从 std::function 传递到 Linux 克隆?
- 如何从类成员函数返回指针,例如 size_t * class :: function(); 并使用类析构函数 ~size
- std::函数指针错误:无法将 &A::a 转换为类型 std::function<>&&
- std::function是如何使指向成员函数的指针工作的
- void *function() 是指向函数的指针还是返回 void* 的函数?
- 如何将 std::function 传递为函数指针?
- 将 boost::function 与指向派生类的共享指针的参数一起使用
- 我可以将函数指针 void* 强制转换为 std::function 吗?
- 将指针传递给 std::function<void()>
- 将 std::function 对象分配给 c 函数指针
- 无法使用 std::function 作为参数类型(需要函数指针版本)宁愿像 STL 这样的模板,但随后它无法推断参数
- 将指向成员函数的指针转换为 std::function
- 将(部分)模板化的模板函数作为std::function(或函数指针)传递
- 如何从“boost::function”中获取 C 指针(如 'var (*)(vo
- 为什么 std::function 不是有效的模板参数,而函数指针是?
- 指向多个参数的函数指针 C++11 std::function:模板化 GetProcAddress
- G++ 4.8.2:无法从函数指针转换为 std::function<>
- 使用 vs typedef 指针到noexcept-function不一致
- 断言一个与std::function兼容的函数指针
- c++将Lambdas与vector中的Function指针区分开来