web-dev-qa-db-fra.com

Modèles de modèles Variadic et transfert parfait

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 .

46
Peter Alexander

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]$
37

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 */ }
7
Luc Danton

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.

3
Puppy