8
votes

Constructeur de modèle C ++ ne compilera pas

Comment se fait-il que je ne puisse pas instancier un objet de type FOO avec le constructeur ci-dessus?

J'ai une barre de classe qui utilise un TypeDef interne (comme solution de contournement pour "Templatey Typedfs") et l'intention de l'utiliser dans un constructeur comme ci-dessous (cas 1). Cependant, je ne semble pas l'obtenir pour compiler. Est-ce légal C ++? Cas 2 semble suggérer que le problème est lié à la TypeDEF dans la barre. P>

Comment puis-je définir un constructeur qui acceptera STD :: Vecteurs d'objets avec le type de barre de type? P>

#include <vector>
#include <iostream>
#include <utility>

template <typename T>
struct Bar
{
    typedef std::pair<T, T> type; // or anything else that uses T
};

struct Foo
{
    Foo() {}

    // CASE 1: doesn't compile
    template <typename T> explicit Foo( const std::vector<typename Bar<T>::type>& data )
    {
        std::cout << "Hello\n";
    }

    //// CASE 2: compiles, but it's not what I want
    //template <typename T> explicit Foo( const std::vector<Bar<T> >& data )
    //{
    //  std::cout << "Hello\n";
    //}
};

int main()
{
    std::vector<Bar<int>::type> v; // for CASE 1
    //std::vector<Bar<int> > v; // for CASE 2

    Foo f( v );
    return 0;
}


3 commentaires

Pouvez-vous poster la sortie d'erreur?


VC ++ confond mon constructeur avec le constructeur de copie et écrit: 'FOO :: FOO (Cons FOO &)' ne peut pas convertir le paramètre 1 de 'std :: vecteur <_ty>' to 'const FOO &' GCC Sorties: Aucune fonction correspondante pour Appelez à 'foo :: foo (std :: vecteur > &)'


Le compilateur Intel C ++ donne l'avertissement utile et utile sur la ligne avec la déclaration du constructeur: AVERTISSEMENT # 488: paramètre de modèle " t " n'est pas utilisé pour déclarer les types de paramètres de modèle de fonction " foo :: foo (const std :: vecteur :: type, std :: allocator :: Type >> &) "


4 Réponses :


4
votes

Votre constructeur est le suivant:

template <typename B> 
explicit 
Foo( const std::vector<B>& data )


1 commentaires

Ah, Luc a gentiment fourni un chapitre et un verset à ma déclaration plutôt vague: Stackoverflow.com/Questtions/2140025/...



11
votes

Selon le paragraphe 14.8.2.1 de la norme C ++, lorsqu'un paramètre de modèle n'est utilisé que dans un contexte non déduit, l'argument de modèle correspondant ne peut pas être déduit:

Si un paramètre-paramètre n'est utilisé dans aucun des paramètres de fonction d'un modèle de fonction ou n'est utilisé que dans un contexte non déduit, son argument-argument correspondant ne peut pas être déduit d'un appel de fonction et de l'argument template doit être explicitement spécifié.

La définition des contextes non éduqués, comme indiqué dans §14.8.2.4:

Les contextes non éduqués sont:

  • Le SPÉCIFICATEUR DE NOM NETTÉ d'un type spécifié à l'aide d'un ID qualifié .

  • un type qui est un template-identifiant dans une ou plusieurs des arguments (EM> est une expression qui fait référence à un modèle modèle-paramètre .

    dans bar :: Type , bar est un spécificateur de nom niché et donc Un contexte non déduit, vous devez donc spécifier explicitement l'argument de modèle lorsque vous appelez le constructeur ... ce qui n'est pas possible (c'est-à-dire que vous ne pouvez pas écrire foo f (v)

    Je suppose que le compilateur ne peut pas déduire l'argument du modèle car ce serait au moins lourd, et plus probablement impossible: l'imagination est spécialisée: xxx

    j'ai un ambiguïté lors de l'appelant le constructeur de FOO avec std :: vecteur > : Si l'argument de modèle doit être int ou char ? Et même s'il n'y avait pas d'ambiguïté de ce type, vous pouvez facilement voir que le compilateur devait instantiaire de la barre avec potentiellement tout type avant de trouver l'instanciation avec le bon Typedef (eh bien, je ne suis pas si sûr que les déclarations sont vraiment pertinentes depuis que je suis souvent Découvrez les compilateurs pour être beaucoup plus intelligents que je pensais: -)!)


1 commentaires

Vous pourriez également citer 14.8.2.4/4, qui nomme les deux contextes non éduqués.



0
votes

Je pense que la seule raison de cela est que vous souhaitez instancier une barre de type correspondant au lieu d'impressionner "Hello".

Peut-être que vous pourriez essayer de mapper les types dans la direction inversée (le type de déduction inversée que vous avez espérant que le compilateur serait capable d'exécuter): xxx


0 commentaires

0
votes

Quelque chose comme ça peut-être pour vous?

#include <vector>
#include <iostream>
#include <utility>
#include <boost/static_assert.hpp>

template <typename T>
struct Bar
{
    typedef std::pair<T, T> type; // or anything else that uses T
    enum {val = 42};
};

template <typename T>
struct Traits
{
    enum {allowed = false};
};

template <typename T>
struct Traits<std::pair<T, T> >
{
    enum {allowed = true};
    typedef Bar<T> BarType;
};

struct Foo
{
    Foo() {}

    template <typename T> explicit Foo( const std::vector<T>& data )
    {
        BOOST_STATIC_ASSERT(Traits<T>::allowed);
        typedef typename Traits<T>::BarType BarType;
        std::cout << BarType::val << std::endl;
    }
};

int main()
{
    std::vector<Bar<int>::type> v;
    std::vector<float> v2;

    Foo f( v );
//    Foo f2( v2 ); // Compile error
    return 0;
}


0 commentaires