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
的指针非const
void
。 kolbek
的参数采用 void const*
- 指向 const void
的指针。那些不是同一类型的。您可以进行从前者到后者的资格转换,但不能反过来(您将放弃 const
!)。这是你的编译器错误。
最简单的解决方案不是没有 Boom
添加 const
。这是不必要的。使用提供的 T
并使用 Boom<const void*>
。
所以,我有一个模板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
的指针非const
void
。 kolbek
的参数采用 void const*
- 指向 const void
的指针。那些不是同一类型的。您可以进行从前者到后者的资格转换,但不能反过来(您将放弃 const
!)。这是你的编译器错误。
最简单的解决方案不是没有 Boom
添加 const
。这是不必要的。使用提供的 T
并使用 Boom<const void*>
。