Impossible d'instancier des modèles de fonction qui utilise decltype pour en déduire le type de retour, si elle est appelée à l'intérieur d'un lambda?
-
22-09-2019 - |
Question
Je suis en train d'utiliser C ++ 0x, et en particulier l'expression lambda et decltype pour simplifier une partie de mon code, en utilisant le compilateur RC MSVC10.
J'ai couru dans le problème suivant très étrange:
template <typename F>
auto foo(F f) -> decltype(f()){
return f();
}
template <typename F>
void bar(F f){
f();
}
int main() {
bar([](){
foo([]() { }); // error C2893: Failed to specialize function template ''unknown-type' foo(F)'
});
}
Comme l'indique le commentaire, le compilateur génère une erreur sur la ligne foo([]() { })
.
Je déteste crier « bug du compilateur », mais je ne vois vraiment pas une bonne explication pour cette erreur.
Apparemment, alors que dans l'expression lambda externe, le compilateur ne peut pas spécialiser le modèle de fonction foo
pour le lambda intérieur.
Cependant, si la définition de foo
est modifiée pour coder le type de retour, comme ceci:
template <typename F>
void foo(F f){
return f();
}
puis tout compile très bien.
Y at-il une certaine bizarrerie obscure de decltype lorsqu'il est utilisé pour en déduire le type de retour des paramètres d'expression lambda dans le cadre d'un autre lambda que je ne suis pas au courant?
La solution
Ce ne sont que des cas de test pour les gens à observer.
Travaux
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
void dummy() {}
int main()
{
auto x = []()
{ // non-lambda parameter
foo(dummy);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto f = [](){};
auto x = [&]()
{ // pre-defined lambda
foo(f);
};
}
Fails
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-argument lambda
foo([]{});
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-scope lambda
auto f = []{};
foo(f);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-scope lambda, explicit return
// (explicit return type fails too, `-> void`)
auto f = [](){ return; };
foo(f);
};
}
template <typename F>
auto foo(F f) -> decltype(f())
{
return f();
}
int main()
{
auto x = []()
{ // in-argument lambda, explicit return non-void
// (explicit return type fails too, `-> int`)
foo([]{ return 5; });
};
}
Il ne semble pas avoir à faire avec la portée et le type de (?) void
du lambda interne, même si explicite.
Autres conseils
La nature « auto » est compilateur permet de calculer le type. Mais votre premier exemple est contient des références récurrentes sur l'autre, afin de calculer automatiquement de foo de vous besoin de la barre et de créer une instance de bar, vous avez besoin du foo.
D'autre part deuxième exemple indique explicitement le compilateur: « Il doit être un pointeur à la fonction, si calme vers le bas pendant un certain temps ». Étant donné que le pointeur de fonction est compilateur de type bien calculé sait ce qui sera réservé exactement. Juste pour analogique: comparer déclaration avant de membre
struct A; //forward
...
A a1; //this is an error
A *a2; //this is correct since pointer calculated in bytes