2010-09-05 6 views
8

Comment peut-on réaliser le auto fonctionnalité de mot-clé sans utiliser C++ 0x standard?Modèle auto fait main (sans utiliser C++ 0x)

for(std::deque<std::pair<int, int> >::iterator it = points.begin(); 
    it != points.end(); ++it) 
{ 
    ... 
} 

Peut-être que cette classe:

class AUTO 
{ 
public: 
    template <typename T1> 
    AUTO(T1); 

    template <typename T2> 
    operator T2(); 
}; 

Avec une telle utilisation:

for(AUTO it = points.begin(); it != points.end(); ++it) 
{ 
    ... 
} 

Mais, T1 et T2 sont différents. Comment déplacer des informations sur T1 à opérateur T2()? Est-ce vraiment possible?

Répondre

12

Si une extension de bibliothèque était facilement implémentable, il n'y aurait pas eu besoin d'une extension de langage. Voir N1607 pour plus de détails sur la proposition automatique.

Toutefois, le article sur la macro Boost.Foreach (sorte de faire ce que vous voulez) peut aider à comprendre les problèmes liés à une telle implémentation.

Qu'est-ce que BOOST_FOREACH?

En C++, l'écriture d'une boucle qui itère sur une séquence est fastidieuse. Nous pouvons soit utiliser itérateurs, ce qui nécessite une quantité considérable de plaque de la chaudière, ou nous pouvons utiliser le std :: for_each() algorithme et déplacer notre corps en boucle dans un prédicat, qui ne nécessite pas moins passe-partout et nous oblige à déplacer notre logique loin de l'endroit où il sera utilisé. En revanche, d'autres langages, comme Perl, fournissent un construit "foreach" dédié qui automatise ce processus. BOOST_FOREACH est juste une telle construction pour C++. Il itère sur des séquences pour nous, nous libérant de en traitant directement avec les itérateurs ou d'écrire des prédicats. BOOST_FOREACH est conçu pour la facilité d'utilisation et l'efficacité. Il n'effectue aucune allocation dynamique, n'appelle aucun appels de fonction ou appels et ne fait aucun appel qui n'est pas transparent pour l'optimiseur du compilateur . Il en résulte génération de code quasi-optimale; la performance de BOOST_FOREACH est généralement à quelques pourcents de la boucle équivalente codée à la main. Et bien que BOOST_FOREACH soit une macro, il est remarquablement bien comporté. Il évalue ses arguments exactement une fois, conduisant à aucune mauvaise surprise.

+0

Je ne pense à la mise en œuvre que pour l'utilisation de for for like like. Le mot-clé auto C++ 0x a beaucoup d'usages ... Merci pour le lien, je vais lire. – k06a

+4

@ k06a: Il existe une forte opposition en C++ pour implémenter quelque chose comme une nouvelle fonctionnalité de langage quand il peut être implémenté dans une bibliothèque. Donc, si quelque chose finit dans la langue, vous pouvez être sûr que personne n'a trouvé le moyen de le faire correctement dans une bibliothèque. (Par exemple, ce que 'std :: function' et' std :: bind' font est construit dans le langage dans beaucoup d'autres langages, mais c'est une fonction de bibliothèque en C++.) – sbi

+1

Je me suis toujours demandé pourquoi BOOST_FOREACH est un petit pourcentage loin d'une boucle "codée à la main". –

10

Il y a une BOOST_AUTO macro que plus ou moins fait ce que le mot clé auto ... Cependant, un coup d'oeil à son application vous dira qu'il est beaucoup mieux de trouver un moyen d'utiliser C++ 0x:>

+0

Merci pour le lien. Lecture ... – k06a

+0

De plus, si le compilateur ne supporte pas decltype ou typeof, BOOST_AUTO ne sera capable de gérer que les types intégrés ainsi que de nombreux types de bibliothèques standard. D'autres types définis par l'utilisateur doivent être "enregistrés" pour que BOOST_AUTO les reconnaisse - si je me souviens bien. – sellibitze

2

Le problème le plus immédiat est d'obtenir des informations du type déduit à une déclaration de membre de données.

class AUTO 
{ 
public: 
    template <typename T1> 
    AUTO(T1); 

    T1 state; // eg deque<...>::iterator - need this! 
}; 

C'est clairement ne va pas se produire parce que l'objet AUTO doit être attribué avant que la fonction est appelée. Étant donné typeof ou decltype, ce n'est pas si difficile.

#define AUTO(name, initializer) typeof(initializer) name = initializer 

Bien sûr, cela a beaucoup de restrictions. Et typeof n'est pas standard. Avec la prise en charge de plusieurs compilateurs, ce serait probablement la base de ces outils Boost.

3

Vous pouvez utiliser ces macros pour contourner ce problème de manière conforme à la norme.

#define DEF_DED(D, E) any_base const & D = make_any_concrete((E)) 
#define DED(D, E) get_t(D, true ? ded_ty() : get_idt((E))) 

template<typename T> struct id { 
    typedef T type; 
}; 

template<typename T> 
id<T> get_idt(T t) { return id<T>(); } 

struct any_base { }; 

template<typename D> 
struct any_concrete : any_base { 
    any_concrete(D d):d(d) {} 
    mutable D d; 
}; 

template<typename T> 
any_concrete<T> make_any_concrete(T x) { return any_concrete<T>(x); } 

struct ded_ty { 
    template<typename T> 
    operator id<T>() { return id<T>(); } 
}; 

template<typename T> 
T &get_t(any_base const &b, id<T>) { return static_cast<any_concrete<T> const&>(b).d; } 

Ainsi, votre boucle for devient

for(DEF_DED(it, points.begin()); 
    DED(it, points.begin()) != points.end(); 
    ++DED(it, points.begin())) 
{ 
    ... 
} 

Le crédit va à Conditional Love: FOREACH Redux, par Eric Niebler. Je ne sais pas si cela vaut vraiment la peine si :)