【问题标题】:How can I cast "const void*" to the function pointer in C++11?如何将“const void *”转换为 C++11 中的函数指针?
【发布时间】:2015-04-15 22:42:01
【问题描述】:

我想将一些const void*对象转换成函数指针:

std::unordered_map<std::string, const void*> originals_;

template <typename R, typename... Args>
R CallOriginal(const std::string& name, Args... args) {
  return reinterpret_cast<R (*const)(Args...)>(originals_[name])(args...);
}

但是,令我惊讶的是,我收到以下错误消息:

错误:将“mapped_type”(又名“const void *”)重新解释为 'int (*const)(int)' 抛弃限定符

首先,使用const 函数指针是否有意义? 如果是这样,那我怎样才能合法地进行选角?

【问题讨论】:

  • 你为什么要强制指向const void*的函数指针首先将它们存储在地图中?为什么不只存储函数指针?
  • 因为我想存储指向具有不同签名的函数的指针。此外,我用来操作函数指针的库确实将它们转换为void* 并接受它们为void const*
  • 这听起来像是个糟糕的主意。由于函数类型在编译时是已知的,因此它们的数量只能是有限的,因此您应该为每种类型都有一个单独的映射。不要对抗类型系统;让它为你工作。我一直不明白为什么人们试图将 C++ 当作一种动态类型的语言来使用。
  • @Brian 问题不在于想法,而在于语法和好奇心。而且我不希望每个单独签名的映射,我希望所有函数替换的映射按其名称 - 不要将唯一的函数指针存储在单独的变量中,否则,这真的很糟糕。我也使用第三方 C 库,AFAIK 在 C 中将所有内容转换为 void* 并不像在 C++ 中那么糟糕。
  • intel 15.0.2 也允许这样做。当然,关于这种转换的一切都是实现定义的(根据5.2.10[expr.reinterpret.cast]/8

标签: c++ c++11 casting constants function-pointers


【解决方案1】:

要通过名称调用任何函数,您可以使用 std::any 结合标准库仿函数 std::function

请注意,调用者必须知道签名,例如参数类型和返回类型不能推导出来。

一个例子:

#include <any>
#include <functional>
#include <string>
#include <unordered_map>

#include <iostream>

static int foo(int a, const std::string& b) {
    std::cout << "foo(" << a << ',' << b << ");" << std::endl;
    return 0;
}

static void bar(float a, const std::string& b) {
    std::cout << "bar(" << a << ',' << b << ");" << std::endl;
}

class call_function_by_name {
public:
    explicit call_function_by_name(std::unordered_map<std::string, std::any>&& table):
        table_(table)
    {}
    template <typename R,typename... ArgTypes>
    R call(const std::string& name,ArgTypes... args) const {
       typedef std::function<R(ArgTypes...)> functor_t;
       std::any anyf = table_.at(name);
       // call function by name
       functor_t functor = std::any_cast<functor_t>( anyf ) ;
       return functor( args... );
    }
private:
    std::unordered_map<std::string, std::any> table_;
};


int main(int argc, const char** argv)
{

    std::unordered_map<std::string, std::any> exportTable;
    exportTable.emplace("foo", std::function<int(int,const std::string&)>(foo) );
    exportTable.emplace("bar", std::function<void(float,const std::string&)>(bar) );

    call_function_by_name bus( std::move(exportTable) );
    int ret = bus.call<int,int,const std::string&>("foo", 1, std::string("bus foo") );
    std::cout << "Foo returned " << ret << std::endl;
    bus.call<void,float,const std::string&>("bar", 2.0F, "bus bar");

    return 0;
}

【讨论】:

    【解决方案2】:

    您想擦除函数签名并只存储函数指针。

    为此,您可以将函数指针转换为其他函数指针,例如 typedef void(*p)()

    C++ 可以在数据内存和代码内存不交互并且指针大小不同的架构上工作。所以将函数指针转换为数据指针一般是不安全的

    【讨论】:

      猜你喜欢
      • 2012-11-21
      • 1970-01-01
      • 2010-12-14
      • 1970-01-01
      • 2011-07-31
      • 2018-12-10
      • 1970-01-01
      • 1970-01-01
      • 2011-10-27
      相关资源
      最近更新 更多