#c #templates #variadic-templates #member-function-pointers #template-argument-deduction
#c #шаблоны #переменные-шаблоны #указатель на член #шаблон-аргумент-вычитание
Вопрос:
template<typename T, typename F, typename ...Args>
auto f(F h, Argsamp;amp;... args) -> decltype(h(args...)) {
T* t = new T(); // Don't worry, my actual code doesn't do this
return (t->h)(args...);
}
struct G {
int g() {
return 5;
}
};
int main() {
int k = f<G>(amp;G::g);
}
Компилятор Microsoft говорит error C2672: 'f': no matching overloaded function found
и error C2893: Failed to specialize function template 'unknown-type f(F,Args amp;amp;...)'
.
Компилятор Clang сообщает note: candidate template ignored: substitution failure [with T = G, F = int (G::*)(), Args = <>]: called object type 'int (G::*)()' is not a function or function pointer
и error: no matching function for call to 'f'
.
Я почти уверен, что int (G::*)()
это указатель на функцию … ? Что я упускаю? (Все это отлично работало до того, как я добавил возвращаемый тип.)
Комментарии:
1. Компилятор рассказывает вам все. Вы не можете вызвать
h(...)
, потому чтоh
она не вызывается сама по себе, когдаh
является указателем на член. Если вы используете C 14, проще всего было бы просто опустить тип возвращаемого значения traliling.2. Я не понимаю, как это сработало. Что вы подразумеваете под тем, что h не может быть вызван сам по себе?
3. О, подождите, я понимаю, вы не можете вызвать просто h(), вам нужно t-> h.
4. Вы можете использовать что-то вроде
decltype((std::declval<T>().*h)(args...))
Ответ №1:
Я почти уверен, что
int (G::*)()
это указатель на функцию … ? Что я упускаю?
Не совсем точно: int (G::*)()
является указателем на нестатический метод. Это не совсем одно и то же, и для ее вызова требуется немного другой синтаксис.
Итак, вместо
return (t->h)(args...);
вы должны добавить *
и вызвать h()
следующим образом
return (t->*h)(args...);
// ........^ add this *
decltype()
Также неверно. Если вы можете использовать хотя бы C 14, вы можете избежать этого и просто использовать auto
в качестве возвращаемого типа
template <typename T, typename F, typename ...Args>
auto f (F h, Argsamp;amp;... args) {
T* t = new T();
return (t->*h)(args...);
}
в противном случае, если вам необходимо использовать C 11, вы можете включить <utility>
и использовать std::declval()
следующим образом
template <typename T, typename F, typename ...Args>
auto f(F h, Argsamp;amp;... args) -> decltype((std::declval<T*>()->*h)(args...)) {
T* t = new T(); // .................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return (t->*h)(args...);
}
Но есть другой способ написать вашу f()
функцию: вывести возвращаемый тип (таким образом, избегая auto
, decltype()
и std::declval()
) и аргументы h()
Вы можете написать f()
следующим образом
template<typename R, typename T, typename ... As1, typename ... As2>
R f(R(T::*h)(As1...), As2 amp;amp; ... args) {
T* t = new T();
return (t->*h)(args...);
}
и вы избегаете явного G
типа, вызывающего ее
int k = f(amp;G::g);
// .....^^^^^^^^ no more explicit <G> needed
поскольку T
тип шаблона выводится из аргумента amp;G::g
.