std :: is_invocable - false, но std :: invoke работает

Кажется, что следующий вывод программы противоречит самому себе:

#include <type_traits>
#include <iostream>
#include <functional>

void foo(int&){ std::cout << "called\n"; }

int main() {
    int a;
    foo(a);
    std::cout << std::is_invocable_v<decltype(foo), decltype(a)> << std::endl;
    std::invoke(foo, a);
}

Выход:

called
0
called

Кажется, что я вызываю функцию, которая не является invocable? Что здесь происходит?

Ответ 1

decltype(a) - int. Это соответствует вызову f с int prvalue - что-то вроде f(7). Это действительно не компилируется, потому что ссылка non- const lvalue не может привязываться к значению prvalue.

То, что вы делаете в main - это вызов f с lvalue, a, к которому ссылка может привязываться просто отлично.

Чтобы получить правильный результат из std::is_invocable, используйте форму выражения decltype, добавив круглые скобки:

std::is_invocable_v<decltype(foo), decltype((a))>
//                                          ^ ^