Domanda

Ecco la classe foo:

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

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

Ecco la barra di classe:

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

È la sintassi corretta per ereditare i costruttori?Se uso "using foo :: foo;"quindi il compilatore di Visual C ++ 2010 muore. Quindi, in pratica, come ereditare i costruttori dalle classi di modelli in VC ++ 2010?

È stato utile?

Soluzione

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

Per consentire un'analisi corretta, è necessario inserire template prima di foo<T>;, per dire al compilatore che foo deve essere considerato come un nome di modello (non può esaminare foo<T> per dirlo a se stesso, poiché T è sconosciuto). Ma l'utilizzo di ::template non è consentito in una dichiarazione using. Il nome inoltre non si riferisce a tutti i costruttori di bar: invece, farebbe riferimento a una specifica specializzazione del modello di funzione del costruttore (T è l'argomento del modello) di tale costruttore come segue

template<typename T>
foo();

Inoltre, non è valido per una dichiarazione using utilizzare un template-id (come foo<T>) come nome (che in effetti gli vieta di fare riferimento alla specializzazione del modello di funzione, con l'aggiunta del divieto di conversione dei nomi delle specializzazioni dei modelli di funzione dichiarate ), quindi anche se si corregge il problema di analisi utilizzando ::template (se fosse possibile), a questo punto si verificherà comunque un errore.

Quando sono stati introdotti costruttori ereditati, sono state aggiunte regole speciali che consentono di fare riferimento a un costruttore utilizzando una regola sintattica: se si dispone di un id qualificato (che fondamentalmente un nome qualificato utilizzando ...::...) e l'ultimo qualificato prima dei nomi delle parti finali una classe specifica, quindi puoi denotare il / i costruttore / i di quella classe in due modi aggiuntivi:

  • Se la classe è stata denominata utilizzando un template-id (un nome del modulo foo<T>) e la parte finale corrisponde al nome del modello (quindi, foo<T>::foo o TTP<T>::TTP con TTP come parametro del modello).
  • Se la parte finale corrisponde al nome della classe (quindi, foo::foo o T::T, con T come parametro del modello).

Queste due regole aggiuntive sono attive solo in una dichiarazione using. E naturalmente non erano presenti in C ++ 03. L'altra regola che era presente anche in C ++ 03 è: se la parte finale nomina il nome della classe inserito, allora questo nome completo si riferisce anche al costruttore:

  • foo::foo funzionerebbe quindi. Ma solo con questa regola, T::T (dove T denota la classe foo) non funzionerebbe, perché foo non ha un membro chiamato T.

Pertanto, con le regole speciali in atto puoi scrivere

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

Anche il secondo è valido: foo è il nome della classe iniettato che è stato iniettato nella classe base foo<T> ed ereditato in bar. Ci riferiamo a quel nome con bar::foo, quindi aggiungiamo l'ultima parte foo, che si riferisce di nuovo al nome della classe inserito, per denotare il / i costruttore / i di `foo.

Ora capisci perché il nome iniziale che hai provato farebbe riferimento a una specializzazione del modello di funzione del costruttore (se fosse consentito): poiché la parte foo<T>::foo nominerebbe tutti i costruttori e il <T> che seguirebbe filtrerebbe il template e passa l'argomento type.

Altri suggerimenti

Se il tuo compilatore non supporta ancora l'ereditarietà dei costruttori, ma supporta macro variadiche, modelli variadici e riferimenti rvalue e un type_trait davvero utile, ecco una soluzione alternativa davvero decente:

#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';
}

Se non hai ancora is_constructible, l'idea di base funziona senza di essa, ma il "costruttore ereditato" sarà eccessivamente avido.

non è necessario il secondo parametro del modello;

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

dovrebbe andare

modifica ritengo che funzioni su g ++ - 4.4.1, tuttavia questa dovrebbe essere la sintassi corretta quando la funzione diventa disponibile

Le altre risposte hanno già fatto un buon lavoro nello spiegare come funzionano i costruttori ereditari in C ++ 0x.Tuttavia, al momento della stesura di questo documento, nessun compilatore ha implementato completamente l'intero set di funzionalità C ++ 0x.Sfortunatamente questo significa che VC ++ 2010 non supporta ancora l'ereditarietà dei costruttori.

Lo standard C ++ 0x non è stato ancora pubblicato.La bozza finale dello standard sarà finita traMarzo , ma ISO impiegherà ancora qualche mese per pubblicarlo.Durante questo periodo, gli autori di compilatori stanno implementando funzionalità in modo che siano il più possibile conformi a C ++ 0x quando lo standard sarà finalizzato.

Credo che l'ultima versione di GCC supporti l'ereditarietà dei costruttori, quindi se devi provarla ora, puoi usarla.Ovviamente, il supporto di C ++ 0x è sperimentale e soggetto a modifiche quando vengono rilevati bug, ecc.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top