Pregunta

Esta pregunta es una promoción de un pedido en este hilo .

Usando las definiciones siguiente clase:

template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
    {
        /* do something for foo */
    }
    T Foo_T;        // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl;   // This doesn't work - compiler error is: error: ‘_foo_arg’ was not declared in this scope
    std::cout << Bar<T>::_foo_arg << std::endl;   // This works!
}

Cuando se accede a los miembros de la clase base de la clase de plantilla, parece que siempre tengo que calificar explícitamente los miembros utilizando la sintaxis de la plantilla de estilo de Bar<T>::_foo_arg. Hay alguna manera de evitar esto? ¿Puede un 'utilizar' declaración / Directiva entrar en juego en un método de clase de plantilla para simplificar el código?

Editar:

El problema se resuelve alcance calificando la variable con this-> sintaxis.

¿Fue útil?

Solución

Puede utilizar this-> para dejar claro que se está refiriendo a un miembro de la clase:

void Bar<T>::BarFunc () {
    std::cout << this->_foo_arg << std::endl;
}

Como alternativa, también puede utilizar "using" en el método:

void Bar<T>::BarFunc () {
    using Bar<T>::_foo_arg;             // Might not work in g++, IIRC
    std::cout << _foo_arg << std::endl;
}

Esto deja claro que el compilador que el nombre de miembro depende de los parámetros de plantilla para que se busca para la definición de ese nombre en los lugares correctos. Para más información véase también esta entrada en el C ++ Faq Lite .

Otros consejos

Aquí la clase base no es una clase base no dependiente (que significa uno con un tipo completo que se puede determinar sin conocer las argumentos de plantilla), y _foo_arg es un nombre no dependiente. Estándar C ++ dice que los nombres no dependientes no se buscan en las clases de base dependientes.

Para corregir el código, es suficiente para que el nombre _foo_arg dependiente porque nombres dependientes se pueden buscar sólo en el momento de la creación de instancias, y en ese momento se conocerá la especialización de base exacta que debe ser explorado. Por ejemplo:

// solution#1
std::cout << this->_foo_arg << std::endl;

Una alternativa consiste en introducir una dependencia utilizando un nombre calificado:

// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;

Se debe tener cuidado con esta solución, porque si el nombre no dependiente no calificado se utiliza para formar una llamada de función virtual, entonces la calificación inhibe el mecanismo de llamada virtual y el significado de los cambios en el programa.

Y se puede llevar un nombre de una clase base depende de la clase derivada una vez por using:

// solution#3
template <class T>
class Bar : public Foo<T> {
public:
    ...
    void BarFunc ();
private:
    using Foo<T>::_foo_arg;
};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl;   // works
}

parece funcionar bien en Visual C ++ 2008. He añadido algunas definiciones ficticias para los tipos que usted ha mencionado, pero no dio ninguna fuente para. El resto es exactamente como usted dice. A continuación, una función principal para forzar BarFunc a una instancia y llama.

#include <iostream>

class streamable {};
std::ostream &operator<<(std::ostream &os, streamable &s) { return os; }

class foo_arg_t : public streamable {};
class a_arg_t : public streamable {};
class b_arg_t : public streamable  {};

template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
    {
        /* do something for foo */
    }
    T Foo_T;        // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl; 
    std::cout << Bar<T>::_foo_arg << std::endl;   
}

int main()
{
    Bar<a_arg_t> *b = new Bar<a_arg_t>(foo_arg_t(), a_arg_t());
    b->BarFunc();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top