C ++ - 将带有const参数的函数指针传递给模板类是错误的

时间:2016-05-07 10:08:09

标签: c++ templates callback void-pointers

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

我将该函数的指针传递给模板类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 *指针被错误解释。

2 个答案:

答案 0 :(得分:1)

在注释中提到的情况下,您可以创建帮助器结构以使模板解除引用参数const:

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 ...

答案 1 :(得分:1)

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

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

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