2008-11-15 4 views
3

Je l'ai fait en msvc 2005.pourquoi est-ce légal, C++ typedef func

typedef void (*cleanup_t)(); 

void func(cleanup_t clean) 
{ 
    cleanup_t(); 
} 

Pourquoi est-ce compiler? et ne pas me donner un avertissement? ok, il m'a donné un avertissement de paramètre formel non référencé mais à l'origine je l'ai fait quand clean était dans une classe non il n'y avait pas de paramètre formel non référencé quand ce code me donnait des problèmes.

Qu'est-ce que cleanup_t(); vraiment faire et quel est le point? maintenant pour rire j'ai essayé int() et cela a fonctionné aussi.

Répondre

9

Il est l'exécution d'une initialisation par défaut pour le type de cleanup_t pour créer un temporaire de ce type, et jamais réellement utiliser cette temporaire. C'est un peu comme un appel de constructeur, la partie "MyClass()" de "MyClass c = MyClass();", sauf que les types pointeur-à-fonction n'ont pas de constructeur. Bien sûr, dans mon extrait de code, "MyClass()" ne crée pas nécessairement un temporaire, car c'est une expression d'initialisation. Le "MyClass()" dans "MyClass(). Some_method();" est peut-être une analogie plus proche. "Int()" est une autre façon de dire "int (0)", qui est une autre façon de dire "(int) 0", qui est une autre façon de dire "0". Encore une fois, il affecte à un temporaire, et si c'est l'ensemble de la déclaration alors le temporaire est inutilisé.

Si vous compilez le code dans la question avec -Wall sur GCC, vous obtenez un avertissement "l'instruction n'a aucun effet". Le code qu'une personne faisant ceci pourrait vouloir signifier, "clean();", ne produirait pas cet avertissement parce que bien sûr cela aurait l'effet d'appeler la fonction. Encore une raison de changer les avertissements et de les corriger correctement ;-)

12

Je pense que c'est une expression qui évalue à une valeur par défaut pour un type cleanup_t. En d'autres termes, une expression qui renvoie un pointeur NULL à une fonction qui renvoie void.

en C/C++, expressions sans effets secondaires (qui c'est - je pense) sont des déclarations valides, comme vous pouvez avoir une déclaration comme:

1 + 2; 

Ce n'est pas une erreur de syntaxe, mais certains les compilateurs pourraient donner un avertissement. Ils ne donnent pas souvent un avertissement pour les expressions sans effet secondaire qui renvoient des valeurs NULL ou sont simplement des noms de variables parce que ce type d'expression est souvent utilisé dans les macros à des fins de débogage (comme la macro assert()).

Vous pouvez l'imaginer comme appelant le constructeur par défaut pour le type cleanup_t. Cette syntaxe de type constructeur par défaut pour les types prédéfinis (ou leur typedef) a été ajoutée à C++ afin que les templates puissent définir les éléments du type transmis comme paramètre de template aux valeurs par défaut tout en permettant au paramètre type de template d'être type non défini par l'utilisateur. Il pourrait y avoir d'autres raisons, mais je crois que c'est l'un d'entre eux.

Quelque chose comme:

template <class T> 
class foo 
{ 
    T myT; 

    public: 

    foo() { 
     myT = T(); 
    }; 
}; 

typedef void (*cleanup_t)(); 


class bar 
{ 
}; 


int not_quite_a_cleanup_t_func() 
{ 
    return 1; 
} 


int main() 
{ 
    foo<int> intFoo; 
    foo<cleanup_t> cleanup_t_foo; 
    foo<bar> barFoo; 

    // here I'm going to harp on one of the things I don't like about C++: 
    // 
    // That so many things that look like function calls are not or that 
    // the parens cause subtle behavior changes. 
    // 
    // I believe this is the reason this question was posted to 
    // stackoverflow, so it's not too far off topic. 
    // 
    // Many of these things exist because of backwards compatibility with C or 
    // because they wanted to fit in new features without adding keywords or 
    // new reserved tokens or making the parser even more complex than it already 
    // is. So there are probably good rationales for them. 
    // 
    // But I find it confusing more often than not, and the fact that there 
    // might be a rationale for it doesn't mean I have to like it... 

    cleanup_t cleanup1(); // declares a function named cleanup1 that returns a cleanup_t 

    cleanup_t cleanup2 = cleanup_t(); // cleanup2 is a variable of type cleanup_t that 
             // is default initialized 

    cleanup_t* cleanup3 = new cleanup_t; // cleanup3 is a pointer to type cleanup_t that 
              // is initialized to point to memory that is 
              // *not* initialized 

    cleanup_t* cleanup4 = new cleanup_t(); // cleanup4 is a pointer to type cleanup_t that 
              // is initialized to point to memory that *is* 
              // initialized (using default intialization) 

    cleanup2 = cleanup_t(not_quite_a_cleanup_t_func); // explicit type conversion using functional notation 

    cleanup_t(); // the OP's problem 
    cleanup2();  // call the function pointed to by cleanup2 
    (*cleanup2)(); // same thing 

    class cleanup_class 
    { 
     cleanup_t cleanup5; 

    public: 
     cleanup_class() : 
      cleanup5() // class member default initialization 
     { }; 
    }; 
} 
Questions connexes