Cette question sur le modèle générateur d'objet m'a fait réfléchir sur les moyens de l'automatiser.
Essentiellement, je veux automatiser la création de fonctions comme std::make_pair
, std::bind1st
Et std::mem_fun
Afin qu'au lieu d'avoir à écrire une fonction différente pour chaque type de classe de modèle, vous puissiez écrire une seule fonction de modèle de modèle variadique qui gère tous les cas à la fois. L'utilisation de cette fonction serait comme:
make<std::pair>(1, 2); // equivalent to std::make_pair(1, 2)
make<std::binder2nd>(&foo, 3); // equivalent to std::bind2nd(&foo, 3);
Est-il possible d'écrire cette fonction make
? J'ai essayé cela, mais cela ne fonctionne pas dans GCC 4.5 ou 4.6:
template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)
{
return TemplateClass<Args...>(std::forward<Args>(args)...);
}
Si j'essaie d'appeler (par exemple) make<std::pair>(1, 2)
je reçois juste
error: no matching function for call to 'make(int, int)'
Ai-je une mauvaise syntaxe quelque part ici?
Ou est-ce vrai et GCC a tort?
Ou est-ce simplement fondamentalement impossible en C++ 0x?
[Éditer]
La proposition N2555 semble suggérer que cela est autorisé et GCC prétend l'avoir implémenté dans GCC4.4 .
C'est exactement ça. Je m'attendrais à ce que cela fonctionne. Je pense donc que GCC a tort de rejeter cela. FWIW:
#include <utility>
template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)
{
return TemplateClass<Args...>(std::forward<Args>(args)...);
}
int main() {
make<std::pair>(1, 2);
}
// [js@Host2 cpp]$ clang++ -std=c++0x main1.cpp
// [js@Host2 cpp]$
Il s'agit probablement d'une bizarrerie du CCG. Je peux faire fonctionner les éléments suivants avec un instantané de développement (je n'ai pas de copie de 4.6 pour le moment):
template<
template<typename...> class TemplateClass
, typename... Args
, typename Result = TemplateClass<Args...>
// Also works with the arguably more correct
// , typename Result = TemplateClass<
// typename std::decay<Args>::type...
// >
>
Result
make(Args&&... args)
{ /* as before */ }
C'est tout à fait faux - prenez make_shared
, Par exemple. Le point de make_shared
Est qu'il y a des économies d'efficacité d'exécution pour l'utiliser. Mais que se passerait-il si j'essayais d'utiliser make<std::shared_ptr>
? Ne pensez pas que cela fonctionnerait parfaitement. Ou que diriez-vous des types où seuls certains des arguments du constructeur sont des arguments de modèle, et le reste ne l'est pas? Par exemple, make<std::vector, int>(other_vector.begin(), other_vector.end());
- les types d'itérateurs ne participent pas, mais vous les transmettez quand même.
Il est impossible d'écrire une fonction générique make
.
Quant à la norme, eh bien, elle aurait facilement pu être supprimée depuis lors. Vous devez vérifier le FDIS.