【问题标题】:Calling Const function pointer调用 const 函数指针
【发布时间】:2016-08-03 15:45:55
【问题描述】:

首先我想提一下,这适用于 MSVC,但不适用于 clang。我在 C++11 中使用 Clang。

我有一个函数指针:

typedef void (*Log) (const char* title, const char* msg, const char* file, int line);

我有这个结构:

 struct FunctionList
    {
    protected:
        static const int kNbrMax = 32;
        FunctionList();
        bool Add(const void* f);
        bool Remove(const void* f);

        const void*     m_functions[kNbrMax];
    };

还有这个类:

template<typename T>
struct MessageFunctionList
    : public FunctionList
{
public:
    MessageFunctionList(T defaultFunction)  
    {
        Add(defaultFunction);
    }

    void Call(const char* title,const char* cause,const char* file,int line)
    {
        for (unsigned long i = 0;i < m_nbrUsed;++i)
        {
            reinterpret_cast<T>(m_functions[i])(title,cause,file,line);
        }
    }
}

我是这样创建的:

static void DefaultLogMessageFunction(const char* title,const char* msg,const char* file,int line)
{

}

MessageFunctionList<Log> functionList(DefaultLogMessageFunction)

但我得到编译时错误:

reinterpret_cast 从 'const void ' 到 'void ()(const char *, const char *, const char *, int)' 抛弃了以下行的限定符: reinterpret_cast(m_functions[i])(标题、原因、文件、行);

据我所知,我正在尝试将我的 const 函数列表转换为非 const 值。这是不允许的,这是有道理的。所以我尝试了以下方法:

const void* funcPtr = m_functions[i];
const T call = reinterpret_cast<const T>(funcPtr);
call(title, cause, file, line);

但这也不起作用。

这行得通:

void* funcPtr = const_cast<void*>(m_functions[i]);
T call = reinterpret_cast<T>(funcPtr);
call(title,cause,file,line);

但我想避免使用 const cast。我究竟做错了什么?我怎样才能调用这个 const 函数?还是根本不允许,因为它不知道被调用的函数是否是 const 函数?或者可能是因为我的静态函数不是类的成员,所以不能声明为 const?

【问题讨论】:

  • 请提供minimal reproducible example。我不知道你实际上在做什么。
  • 我错过了什么?包含哪些不必要的内容?我想我已经包括了所有需要的东西?你想要一个压缩的项目吗?我正在尝试存储指向日志函数的函数指针列表。
  • 您缺少一个 MCVE。我正在寻找一个简短的、独立的示例,我可以看到您遇到的编译错误以及您正在尝试做什么。我所看到的只是几个未连接的代码片段,我不明白您要做什么或为什么会失败。
  • godbolt.org/g/RfbrUI 虽然这是一个问题,但它似乎编译得很好。我不确定为什么我的 clang 编译器会失败。

标签: c++ function c++11 constants


【解决方案1】:

您将函数指针存储为const void*

const void*     m_functions[kNbrMax];

而您正在尝试将它们转换为T 并使用reinterpret_cast 调用它:

reinterpret_cast<T>(m_functions[i])(title,cause,file,line);

但是,reinterpret_cast 不能从类型中删除 const 限定符,因此,您应该首先使用 const_cast 删除 const

reinterpret_cast<T>(const_cast<void*>(m_functions[i]))(title,cause,file,line);
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

但是,请注意const_cast 会产生未定义的行为并且不安全。如果原始指针实际上不是T,则调用从reinterpret_cast 返回的函数指针也是如此。

编辑: 您可以调用 const 限定的函数指针,但是,reinterpret_cast 应该包含 const 限定符:

reinterpret_cast<const T>(m_functions[i])(title,cause,file,line);

【讨论】:

  • 谢谢,但我自己在帖子底部提供了相同的解决方案。我不明白为什么我不能存储和调用 const 函数。我试图避免 const cast。
  • 我也试过了,认为它会起作用,但我得到了同样的错误。这很奇怪,因为在线 clang 编译器似乎编译它没有错误。
  • @marsh,在线和离线 g++ 编译器也是如此:coliru.stacked-crooked.com/a/ccf66094fb802e7d
  • @marsh,我不知道,但它看起来像是编译器问题,而不是语言问题。另外,据我所知,将函数指针转换为void* 是未定义的。为什么不直接使用 T 来存储函数指针,只需让基类离开?
  • @marsh,函数指针类型还是可以改变的,检查一下,类型安全:coliru.stacked-crooked.com/a/6759067d687386a6
猜你喜欢
  • 1970-01-01
  • 2016-08-17
  • 1970-01-01
  • 2023-03-20
  • 2012-03-15
  • 2012-03-25
  • 1970-01-01
  • 2011-09-26
  • 1970-01-01
相关资源
最近更新 更多