С++ 11 result_of вывести мой тип функции не удалось

Я пробовал программу ниже:

#include<type_traits>
using namespace std;
template <class F, class R = typename result_of<F()>::type>
R call(F& f) { return f(); }
int answer() { return 42; }

int main()
{
    call(answer); 
    return 0;
}

«вызов (ответ)» не компилируется

VC говорит, что «R call (F &)» не может вывести аргумент шаблона для «R»

GCC говорит | примечание: вывод/подстановка аргумента шаблона не удалась: | ошибка: функция возвращает функцию

Я не уверен, можно ли использовать «имя функции» для шаблонов. Где я ошибся, как заставить мой звонок(ответ) работать?


person Troskyvs    schedule 29.06.2016    source источник


Ответы (3)


Вы можете использовать ссылки для переадресации в следующих случаях:

#include<type_traits>
#include<utility>
#include<cassert>

using namespace std;

template <class F, class R = typename result_of<F()>::type>
R call(F&& f) { return std::forward<F>(f)(); }

int answer() { return 42; }

int main()
{
    assert(call(answer) == 42);
    return 0;
}

Обычно это позволяет избежать неприятностей.

Тем не менее, почему ваш код не работает, прекрасно объяснил @T.C. в его ответе.
См. также комментарии к этому вопросу для получения дополнительной информации.

person skypjack    schedule 29.06.2016
comment
Но почему я не могу вызвать f как lvalue? имя функции всегда не является lvalue? - person Troskyvs; 29.06.2016
comment
Вы можете назвать это как lvalue. В вашем примере, из-за того, как работает вывод типа шаблона, F является типом функции, а не ссылкой на него. Используя ссылки пересылки, F выводится как ссылка на answer. Попробуйте добавить static_assert(std::is_reference<F>::value, "!"); в call в моем примере и в примере @T.C. - person skypjack; 29.06.2016
comment
Еще одним тестом будет добавление std::function<F> func; к call в обоих примерах. Это должно помочь вам понять, что там происходит с выводом типа для F. - person skypjack; 29.06.2016

Вы вызываете f как lvalue, поэтому:

template <class F, class R = typename result_of<F&()>::type>
//                                               ^
R call(F& f) { return f(); }
person T.C.    schedule 29.06.2016
comment
Я не совсем понимаю этот результат_of‹F&()›::type. Что здесь означает F&()? - person Troskyvs; 29.06.2016

Я полагаю, вы могли бы избежать второго аргумента шаблона и использовать комбинацию auto и decltype().

Что-то типа

#include<type_traits>

using namespace std;

template <class F>
auto call(F& f) -> decltype( f() )
 { return f(); } 

int answer()
 { return 42; }

int main()
{
    call(answer); 

    return 0;
}

Если вы (когда вы) можете использовать С++ 14, вы можете использовать просто auto

template <class F>
auto call(F& f)
 { return f(); } 

p.s.: извините за мой плохой английский.

person max66    schedule 29.06.2016
comment
Эти две версии делают разные вещи. - person T.C.; 29.06.2016
comment
Почему две версии делают разные вещи? - person Troskyvs; 29.06.2016
comment
@Т.С. - вы имеете в виду, что auto может терять константы и ссылки, где decltype(f()) их сохраняет? Так что должно быть decltype(auto) вместо auto в С++ 14? - person max66; 29.06.2016