#c #templates #inheritance #c 98
#c #шаблоны #наследование #c 98
Вопрос:
Кажется, я не могу понять, что происходит с конкретным шаблонным методом.
Аналогичный шаблонный метод уже некоторое время находится в моей кодовой базе и используется таким же образом, как Bar::Bar(IFooamp;)
, с той лишь разницей, что передаваемая функция наследуется.
У меня есть интерфейс IFoo
, который определяет рассматриваемую шаблонную функцию.
struct IFoo {
template<class T>
void doSomething(bool (T::*method)(int), T *instance) {
std::cout << (instance->*method)(5) << "n";
}
};
У меня есть класс Bar
, который является дочерним элементом другого класса
struct Parent {
virtual bool setValue(int a) { return true; }
};
struct Bar : Parent { };
Когда я пытаюсь использовать IFoo::doSomething
компилятор, он просто не видит соответствующую функцию
int main() {
Bar b;
IFoo foo;
foo.doSomething(amp;Bar::setValue, amp;b);
}
Я получаю следующее сообщение
об ошибке компилятора: нет соответствующей функции для вызова « IFoo::doSomething(bool (Parent::*)(int), Bar*)
Что меня действительно удивляет, так это то, что я не получаю предложения кандидата для шаблонной IFoo::doSomething
функции.
Пожалуйста, только решения на C 98.
Комментарии:
1. Не выполняет сам вызов вместо виртуального метода?
2. Мне очень жаль, что вы все еще вынуждены использовать c 98
3.
do
это ключевое слово в C . Вы не можете назвать такой метод4. Один метод do является частным и имеет параметры, отличные от общедоступной версии, которую я пытаюсь использовать.
5. Я отредактирую и переименую метод в моем примере, который не вызывается в моей кодовой базе
Ответ №1:
Как указано в ошибке, тип Bar::setValue
на самом деле bool (Parent::*)(int)
. Это мешает вычету параметра шаблона для doSomething
, потому что у него есть два T
s, которые должны быть одинаковыми. Вы можете помочь компилятору с выводом путем приведения this
:
int main() {
Bar b;
IFoo foo;
foo.doSomething(amp;Bar::setValue, static_cast<Parent*>(amp;b));
}
Спасибо JVApen за указание на то, что в качестве альтернативы вы можете сделать doSomething
более общий, разрешив два разных типа и разрешить Callback
преобразование:
template<class T, class U>
void doSomething(bool (T::*method)(int), U *instance);
Комментарии:
1. В качестве альтернативы можно использовать 2 параметра шаблона и позволить обратному вызову неявно переводить строку в родительский указатель: godbolt.org/z/6adT8x
2. @JVApen спасибо за ссылку. Я думал то же самое, но, по общему признанию, был слишком ленив, чтобы убедиться, что это работает 😉
3. Однако я собирался добавить
static_assert(std::is_base_of_v<T, U>)
, что этого не существовало 22 года назад4. @lancegerday «static_cast требует больших вычислительных затрат» это, должно быть, недоразумение. Почему вы так думаете?
5. Существует также шаблон dark magic «блокировщик дедукции»:
template<class T> struct type_identity { /* stolen from C 20 */ typedef T type; }; template<class T> void doSomething(bool (T::*method)(int), typename type_identity<T>::type *instance);
, в которомdoSomething(amp;Bar::setValue, amp;b)
работает, потому что толькоamp;Bar::setValue
способствует выборуT = Parent
. Затем передача становится неявной.