2016-05-07 1 views
1

Итак, у меня есть класс шаблона, который должен вызвать функцию обратного вызова в какое-то время. Эта функция обратного вызова принимает в качестве аргумента шаблон const T.C++ - Передача указателя функции, принимающего аргумент const в класс шаблона, неверно интерпретируется

Я передаю указатель этой функции классу шаблона 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 * неверно интерпретируются.

+0

Прежде всего вы не можете создать реализацию своих шаблонов внутри файла cpp, так как они не будут связаны ... переместите ваш boom.cpp-контент в ваш файл boom.h –

+1

@WojciechFrohmberg - это неправда. Он явно создает экземпляры двух типов - Boom и Boom . Если они являются типами, которые ему нужны в другом месте, тогда они свяжутся только с прекрасным – Smeeheey

+2

, во-вторых, ваш компилятор видит ваш шаблонный параметр метода callbk как 'void * const', а не' const void * ' –

ответ

1

Ваша проблема связана с запутыванием двух разных const. Вот почему это может быть полезно написать T const вместо const T - это делает текстовую замену не лгать вам.

Boom «s обратный вызов принимает T const который в вашем instatiation является void* const (не const void* !!): это const указатель непредставленных constvoid. Аргумент kolbek занимает void const* - указатель на const void. Это не то же самое. Вы можете сделать квалификационное преобразование от первого к последнему, но не наоборот (вы должны отбросить const!). Это ваша ошибка компилятора.

Простейшее решение не имеет Boom добавить const. Это не нужно. Используйте T, как предусмотрено, и используйте Boom<const void*>.

+0

Я предложил решение с «Boom » в комментарии, но OP заявил, что он использует параметр 'T' более одного раза в реализации« Boom », и один раз он должен быть' const', а в остальных - «т. –

1

В случае, упомянутом в комментарии вы можете создать вспомогательную-структуру, чтобы сделать ваш шаблон разыменовывается параметр сопзЬ:

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 в вашем примере ...

Смежные вопросы