36 votes

std::is_invocable est faux mais std::invoke fonctionne

Le résultat du programme suivant semble se contredire :

#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);
}

La sortie est :

called
0
called

Ce qui me semble être l'invocation d'une fonction qui n'est pas invocable ? Qu'est-ce qui se passe ici ?

1 votes

Basé sur une intuition, est-ce que ça change si foo accepte une référence const lvalue à la place ?

0 votes

@StoryTeller Oui ( coliru.stacked-crooked.com/a/5d8a4615fda8e8b4 ), mais pouvez-vous expliquer pourquoi ?

62voto

Quentin Points 3904

decltype(a) es int . Cela correspond à invoquer f avec un int prvalue -- quelque chose comme f(7) . Celui-ci ne compile en effet pas, parce qu'un non const La référence lvalue ne peut pas se lier à une prvalue.

Ce que vous faites à la place dans main appelle f avec un lvalue , a à laquelle la référence peut se lier sans problème.

Pour obtenir le résultat correct de std::is_invocable utiliser la forme d'expression de decltype en ajoutant des parenthèses :

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

11 votes

Ou utilisez decltype((a)) dans ce cas :-S

0 votes

@KerrekSB oui, définitivement. Je ne sais pas pourquoi cela m'a échappé.

0 votes

Si int signifie un prvalue int, cela ne ferait-il pas a un xvalue puisqu'il s'agit d'un nom prvalue ? Ou est-ce que je ne comprends pas bien la nature des catégories de valeurs ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X