Ошибка вызова шаблонной функции указателя на член с типом возврата - PullRequest
1 голос
/ 08 марта 2019
template<typename T, typename F, typename ...Args>
auto f(F h, Args&&... 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>(&G::g);
}

Компилятор Microsoft говорит error C2672: 'f': no matching overloaded function found и error C2893: Failed to specialize function template 'unknown-type f(F,Args &&...)'.

Компилятор 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 Ответ

2 голосов
/ 08 марта 2019

Я почти уверен, 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, Args&&... 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, Args&&... 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 && ... args) {
    T* t = new T();
    return (t->*h)(args...);
}

, и вы избежите явного вызова типа G, вызывающего его

int k = f(&G::g);
// .....^^^^^^^^   no more explicit <G> needed

потому что тип шаблона T выводится из аргумента &G::g.

...