Pergunta

Esta questão é uma promoção do único perguntou em esta discussão .

Usando as definições seguintes classes:

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!
}

Ao acessar os membros da classe base do modelo de classe, parece que eu sempre deve qualificar explicitamente os membros usando a sintaxe de estilo modelo de Bar<T>::_foo_arg. Há alguma maneira de evitar isto? um 'usando' declaração / directiva podem entrar em jogo em um método de classe de modelo para simplificar o código?

Editar:

A questão escopo é resolvido, qualificando a variável com this-> sintaxe.

Foi útil?

Solução

Você pode usar this-> para deixar claro que você está se referindo a um membro da classe:

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

Como alternativa, você também pode usar "using" no método:

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

Isso deixa claro para o compilador que o nome do membro depende dos parâmetros do modelo para que ele procura para a definição desse nome nos lugares certos. Para mais informações veja também esta entrada no C ++ FAQ Lite .

Outras dicas

Aqui, a classe base não é uma classe base não dependente (o que significa um com um tipo completo que pode ser determinada sem conhecer os argumentos de modelo), e _foo_arg é um nome não dependente. Padrão C ++ diz que os nomes não dependentes não são procurados na base classes dependentes.

Para corrigir o código, basta fazer o nome _foo_arg dependente porque os nomes dependentes podem ser consultados apenas no momento da instanciação, e naquele tempo a especialização de base exata que deve ser explorado será conhecido. Por exemplo:

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

Uma alternativa consiste na introdução de uma dependência utilizando um nome qualificado:

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

É preciso ter cuidado com esta solução, porque se o nome não dependente não qualificado é usado para formar uma chamada de função virtual, em seguida, os inibe de qualificação do mecanismo de chamada virtual e o significado das mudanças do programa.

E você pode trazer um nome de uma classe base dependente na classe derivada uma 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 belo trabalho no Visual C ++ 2008. Eu adicionei algumas definições fictícios para os tipos que você mencionou, mas não deu fonte. O resto é exatamente como você colocá-lo. Em seguida, uma função principal a força BarFunc a ser instanciado e chamado.

#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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top