C ++ 11获取std :: function的指针

时间:2017-02-09 12:03:33

标签: c++ c++11

我想在std::function中存储和识别std::map个对象。 要确定我想使用std::function::target。 如果我使用std::function::target绑定到类中的成员函数,我无法从std::bind获取指针。

#include <functional>
#include <iostream>


using namespace std;
void normal_fun(int a)
{
    std::cout << "hello\n"<<a;
}

class testclass
{
public:
    int b;
    void mytest(int a)
    {
        b = a;
    }
};

uintptr_t getFuncAddress(std::function<void(int)> &f)
{
    uintptr_t returnAddress = reinterpret_cast<uintptr_t>(f.target<void(*)(int)>());
    return returnAddress;
}

int main()
{

    testclass c;
    std::function<void(int)> f1 = bind(&testclass::mytest,&c, placeholders::_1);
    std::function<void(int)> f2 = normal_fun;
    auto addrF1 = getFuncAddress(f1);
    auto addrF2 = getFuncAddress(f2);
}

我怎样才能达到我想做的目的?

4 个答案:

答案 0 :(得分:2)

std::function不是函数指针。它甚至不是指针。

如果您知道std::function中存储的类型,您可以获得指向它存储内容的指针。请注意,这里的指针不是函数指针,而是指向函数指针的指针。

如果您不知道它存储的类型,则不能。

如果您需要<==hash(等),std::function不会为您提供此功能。它的类型会删除(),复制,移动,销毁,输入和回送到原始文件。

您可以使用类型擦除技术来增强std::function这些操作;请注意,二进制操作上的类型擦除通常比类型擦除更复杂。

类型删除某些东西不应该是解决问题的第一步,但它会解决您的问题。在C ++的SO文档中有关于类型擦除的文章。这不是一个初学者。

可能以更简单的方式解决您的潜在问题。

在任何情况下,使用从target返回的类型来订购都不是一个好主意,因为它是指向可能自动存储对象或可能是堆存储对象的指针;其中两个将在无害操作(如移动)下具有显着不同的失效规则。 SBO(小缓冲区优化)目标将与std::function的实例一起移动,而堆分配的目标可能与std::functionstd::move下移动的状态保持一致类似的操作。这真是一团糟。

答案 1 :(得分:1)

std::function的要点是为符合给定签名的可调用对象提供统一的接口和类型。您期望它也提供统一的排序键,但它不会这样做。无法对std::bind返回的函数指针和任意函数对象和可调用对象进行排序。它们是完全不同的东西,比较它们并不合理。允许您执行的所有std::function存储并调用它们。

如果你需要一种排序机制,你必须自己创造一些东西,你就不会从std::function获得它。

答案 2 :(得分:0)

f.target<void(*)(int)>

错误,因为bind返回的类型不是void(*)(int),所以目标永远不会返回非空指针。绑定不返回函数指针。它返回一些指定类型的实现对象。

可以使用decltype获取类型。这有点不正常,但应该是正确的:

f.target<decltype(bind(
  &testclass::mytest,
  (testclass*)nullptr,
  placeholders::_1)
)>
  

但我有问题,如果我有testclass或myOtherClass或其他人类,我在getFuncAddress中不知道

如果您知道包装对象的类型,则只能使用std::function::target。如果选择的数量有限,那么您可以尝试使用每种类型获取目标,直到返回非null。对于任意未知类型,std::function::target对您没有任何用处。

  

我想在std :: map

中存储和识别std :: function对象

我认为你必须使用一些无法从std::function中提取的外部密钥。这意味着如果您希望防止重复,您还需要一种外部方法来保证从键到函数的唯一映射。

答案 3 :(得分:0)

  

我想在std :: map中存储和识别std :: function对象。

我假设您要识别std::function个对象(例如,有选择地调用或删除它们)。 在这种情况下,我使用另一个密钥,例如一个简单的unsigned。 可以使用全局函数:

typedef unsigned Key;

Key genId()
{
  static Key id = 0;
  return ++id;
}

现在,std::function个对象可以与此密钥配对。 API可以授予对配对std::function对象的访问权限,可以使用密钥完成。