Question

Voici Class Foo:

template <typename T>
struct foo
{
    foo()
    {
        t = nullptr;
    }

    foo(T* p, bool flag)
    {
        t = p;
    }
private:
    T* t;
};

Voici la barre de classe:

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

Est-ce une syntaxe correcte pour les constructeurs hérités? Si j'utilise "en utilisant foo :: foo;" Puis le compilateur de Visual C ++ 2010 décède. Donc, fondamentalement, comment hériter des constructeurs à partir de classes de modèles dans VC ++ 2010?

Était-ce utile?

La solution

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

Pour laisser cette analyse correctement, vous devrez insérer template avant le foo<T>;, pour dire au compilateur que foo doit être considéré comme un nom de modèle (il ne peut pas examiner foo<T> se dire, puisque T est inconnu). Mais en utilisant ::template n'est pas autorisé dans une déclaration d'utilisation. Le nom ne fait pas non plus référence à tous les constructeurs de bar: Au lieu de cela, il ferait référence à une spécialisation de modèle de fonction de constructeur spécifique (T L'argument du modèle est-il d'un tel constructeur que suit

template<typename T>
foo();

De plus, il n'est pas valable qu'une déclaration d'utilisation d'utiliser un template-id (Comme foo<T>) Comme son nom (qui l'interdit en effet pour se référer à la spécialisation du modèle de fonction, avec l'ajout d'interdiction de nommer des spécialisations de modèle de fonction de conversion indiqués), même si vous corrigez le problème d'analyse en utilisant ::template (Si cela serait possible), vous seriez toujours erroné à ce stade.

Lorsque des constructeurs hérités ont été introduits, des règles spéciales ont été ajoutées qui permettent de référencer un constructeur en utilisant une règle syntaxique: si vous avez un ID qualifié (qui est essentiellement un nom qualifié en utilisant ...::...), et le dernier qualifié avant la dernière pièce nomme une classe spécifique, alors vous pouvez désigner le ou les constructeurs de cette classe de deux façons supplémentaires:

  • Si la classe a été nommée à l'aide d'un Template-ID (un nom du formulaire foo<T>) et la pièce finale correspond au nom du modèle (donc, foo<T>::foo ou TTP<T>::TTP avec TTP étant un paramètre de modèle de modèle).
  • Si la pièce finale correspond au nom de classe (donc, foo::foo ou T::T, avec T étant un paramètre de modèle).

Ces deux règles supplémentaires ne sont actives que dans une déclaration en utilisant. Et ils n'étaient naturellement pas présents dans C ++ 03. L'autre règle qui était également présente dans C ++ 03 est: si la pièce finale nomme le nom de classe injecté, ce nom qualifié fait également référence au constructeur:

  • foo::foo serait donc de travailler. Mais avec cette règle seule, T::T (où T indique la classe foo) ne fonctionnerait pas, car foo N'a aucun membre appelé T.

Là, avec les règles spéciales en place, vous pouvez écrire

using foo<T>::foo;
using bar::foo::foo; // valid too

Le second est également valable: foo est le nom de classe injecté qui a été injecté dans la classe de base foo<T> et hérité de bar. Nous nous référons à ce nom par bar::foo, puis ajouter la dernière partie foo, qui fait référence au nom de classe injecté, pour désigner le ou les constructeurs de `foo.

Vous comprenez maintenant pourquoi le nom initial que vous avez essayé se référerait à une spécialisation du modèle de fonction de constructeur (si elle devait être autorisée): parce que le foo<T>::foo la partie nommerait tous les constructeurs, et le <T> Cela suivrait alors filtrerait le modèle et passerait l'argument de type.

Autres conseils

Si votre compilateur ne prend pas encore en charge les constructeurs hérités, mais prend en charge les macros variadiques, les modèles variadiques et les références de référence, et un type_trait vraiment pratique, voici une solution de contournement vraiment décente:

#include <type_traits>
#include <utility>
#include <ostream>

enum Color {Red, Blue};

#define USING(Derived, Base)                                 \
    template<typename ...Args,                               \
             typename = typename std::enable_if              \
             <                                               \
                std::is_constructible<Base, Args...>::value  \
             >::type>                                        \
    Derived(Args &&...args)                                  \
        : Base(std::forward<Args>(args)...) { }              \


template<typename Mixin>
class add_color
: public Mixin
{
    Color color;

public:
    USING(add_color, Mixin);

    friend std::ostream& operator<<(std::ostream& os, const add_color& x)
    {
        switch (x.color)
        {
        case Red:
            os << "Red";
            break;
        case Blue:
            os << "Blue";
            break;
        }
        os << ' ' << x.first << ' ' << x.second;
        return os;
    }
};

#include <string>
#include <iostream>

int main()
{
    add_color<std::pair<std::string, int>> x1("five", 5);
    std::cout << "x1 = " << x1 << '\n';
    add_color<std::pair<std::string, int>> x3;
    std::cout << "x3 = " << x3 << '\n';
    add_color<std::pair<std::string, int>> x4 = x1;
    std::cout << "x4 = " << x4 << '\n';
    std::pair<std::string, int> p;
    add_color<std::pair<std::string, int>> x5 = p;
    std::cout << "x5 = " << x5 << '\n';
}

Si vous n'avez pas encore IS_constructible, l'idée de base fonctionne sans elle, mais le "constructeur héréditaire" sera trop gourmand.

Vous n'avez pas besoin du deuxième paramètre de modèle;

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo;
};

devrait faire

Éditer Je me retire que cela fonctionne sur G ++ - 4.4.1, mais ce devrait être la syntaxe correcte lorsque la fonctionnalité devient disponible

Les autres réponses ont déjà fait un bon travail pour expliquer comment fonctionnent les constructeurs hérités de C ++ 0x. Cependant, à ce jour, aucun compilateur n'a complètement implémenté l'intégralité de l'ensemble de fonctionnalités C ++ 0x. Malheureusement, cela signifie que VC ++ 2010 ne prend pas encore en charge les constructeurs hérités.

La norme C ++ 0x n'a pas encore été publiée. Le projet final de la norme sera terminé en mars, mais il faudra encore quelques mois à ISO pour le publier. Pendant ce temps, les scénaristes du compilateur déploient les fonctionnalités afin qu'ils soient aussi conformes au C ++ 0x que possible lorsque la norme est finalisée.

Je crois que la dernière version de GCC prend en charge les constructeurs hérités, donc si vous devez l'essayer maintenant, vous pouvez l'utiliser. Bien sûr, le support C ++ 0x est expérimental et sujet à changer à mesure que les bogues sont trouvés, etc.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top