C++ - 将带有 const 参数的函数指针传递给模板 class 被错误解释

C++ - Passing a function pointer taking const argument to a template class is wrongly interpeted

所以,我有一个模板class,它必须在某个时间调用回调函数。该回调函数将 const T 模板作为参数。

我将该函数的指针传递给模板 class Boom<void*>。但是,该回调的 const T 参数被解释为只是 T

但只有 void* 才是这种情况。

代码:

//main.cpp

void kolbek(const void* val)
{
    if(val)
        printf("Value is: %d\n", *((int*)val));
    else
        printf("Value ptr = NULL\n");
}

int main()
{
    Boom<void*> bomba;
    bomba.setCallback(kolbek); //error!

    int* nuint = new int(5);
    bomba.callCallback((void*)nuint);
    delete nuint;

    return 0;
}

//boom.h

template<typename T>
class Boom
{
private:
    void (*someCallback)(const T) = nullptr;
public:
    Boom(){ }
    ~Boom(){ }

    void setCallback(void (*callbk)(const T));
    void callCallback(const T val);
};

//boom.cpp

template<typename T>
void Boom<T>::setCallback(void (*callbk)(const T))
{
    this->someCallback = callbk;
}

template<typename T>
void Boom<T>::callCallback(const T val)
{
    if(someCallback)
        (*someCallback)(val);
    else
        printf("Bad! Callback's NULL!\n");
}

template class Boom<int>;
template class Boom<void*>;

尝试编译时,抛出错误:

error: invalid conversion from 'void (*)(const void*)' to 'void (*)(void*)' [-fpermissive]
error: initializing argument 1 of 'void Boom<T>::setCallback(void (*)(T)) [with T = void*]' [-fpermissive]

如何解决?似乎只有 void* 指针被错误地解释了。

在评论中提到的情况下,您可以创建辅助结构以使您的模板取消引用参数常量:

template<class T>
struct ptr_constantizer {
 using type = const T;
};

template<class T>
struct ptr_constantizer<T*> {
 using type = const T*;
};

template<typename T>
class Boom
{
private:
    void (*someCallback)(typename ptr_constantizer<T>::type) = nullptr;
public:
    Boom(){ }
    ~Boom(){ }

    void setCallback(void (*callbk)(typename ptr_constantizer<T>::type)) { }
    void callCallback(const T val) { }
};

void foo(const void *ptr) {
}
void fooi(const int non_ptr) {
}

int main() {
   Boom<void *> b;
   Boom<int> bi;
   b.setCallback(&foo);
   bi.setCallback(&fooi);
}

代码假定您使用的是 c++11,就像您在示例中使用的 nullptr...

您的问题来自混淆两个不同的 const。这就是为什么写 T const 而不是 const T 会有所帮助 - 它使文本替换不会骗你。

Boom 的回调采用 T const,在您的实例中是 void* const(不是 const void*!!):它是一个指向 const 的指针非constvoidkolbek 的参数采用 void const* - 指向 const void 的指针。那些不是同一类型的。您可以进行从前者到后者的资格转换,但不能反过来(您将放弃 const!)。这是你的编译器错误。

最简单的解决方案不是没有 Boom 添加 const。这是不必要的。使用提供的 T 并使用 Boom<const void*>