Pergunta

Aqui está a classe foo:

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

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

Aqui está o bar da turma:

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

É a sintaxe correta para herdar construtores?Se eu usar "using foo :: foo;"em seguida, o compilador do Visual C ++ 2010 morre. Então, basicamente, como herdar construtores de classes de modelo no VC ++ 2010?

Foi útil?

Solução

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

Para permitir que isso analise corretamente, você precisaria inserir template antes do foo<T>;, para dizer ao compilador que foo deve ser considerado como um nome de modelo (ele não pode olhar em foo<T> para dizer a si mesmo, uma vez que T é desconhecido). Mas o uso de ::template não é permitido em uma declaração de uso. O nome também não se refere a todos os construtores de bar: em vez disso, ele se referia a uma especialização de modelo de função de construtor específica (T é o argumento do modelo) de tal construtor, como segue

template<typename T>
foo();

Além disso, não é válido para uma declaração de uso usar um template-id (como foo<T>) como seu nome (o que na verdade proíbe que se refira à especialização do modelo de função, com a adição de proibir a conversão de nomes de especializações de modelo de função declarada ), portanto, mesmo que você corrija o problema de análise usando ::template (se for possível), ainda haverá um erro neste ponto.

Quando os construtores herdados foram introduzidos, regras especiais foram adicionadas que permitem fazer referência a um construtor usando uma regra sintática: se você tiver um id qualificado (que basicamente é um nome qualificado usando ...::...) e o último qualificado antes dos nomes das partes finais uma classe específica, então você pode denotar o (s) construtor (es) dessa classe de duas maneiras adicionais:

  • Se a classe foi nomeada usando um template-id (um nome do formulário foo<T>) e a parte final corresponde ao nome do modelo (então, foo<T>::foo ou TTP<T>::TTP com TTP sendo um parâmetro de modelo de modelo).
  • Se a parte final corresponder ao nome da classe (então, foo::foo ou T::T, com T sendo um parâmetro de modelo).

Essas duas regras adicionais só estão ativas em uma declaração de uso. E eles naturalmente não estavam presentes no C ++ 03. A outra regra que também estava presente em C ++ 03 é: Se a parte final nomear o nome da classe injetada, então este nome qualificado também se refere ao construtor:

  • foo::foo funcionaria, portanto. Mas com esta regra sozinha, T::T (onde T denota a classe foo) não funcionaria, porque foo não tem membro chamado T.

Portanto, com as regras especiais em vigor, você pode escrever

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

A segunda também é válida: foo é o nome da classe injetada que foi injetada na classe base foo<T> e herdada por bar. Referimo-nos a esse nome por bar::foo e, em seguida, adicionamos a última parte foo, que se refere ao nome da classe injetada novamente, para denotar o (s) construtor (es) de `foo.

Agora você entende por que o nome inicial que tentou se referir a uma especialização de modelo de função de construtor (se fosse permitido): Porque a parte foo<T>::foo nomearia todos os construtores, e o <T> que se seguiria filtraria o modelo e passe o argumento de tipo.

Outras dicas

Se o seu compilador ainda não suporta construtores herdados, mas suporta macros variadic, templates variadic e referências rvalue, e um type_trait muito útil, aqui está uma solução realmente 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 você ainda não tem is_constructible, a ideia básica funciona sem ele, mas o "construtor herdado" será excessivamente ganancioso.

você não precisa do segundo parâmetro do modelo;

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

deve servir

editar eu retiro que isso funciona no g ++ - 4.4.1, no entanto, esta deve ser a sintaxe correta quando o recurso for disponibilizado

As outras respostas já explicaram como os construtores herdados em C ++ 0x funcionam.No entanto, até o momento em que este livro foi escrito, nenhum compilador implementou completamente todo o conjunto de recursos C ++ 0x.Infelizmente, isso significa que o VC ++ 2010 ainda não oferece suporte a construtores herdados.

O padrão C ++ 0x ainda não foi publicado.O rascunho final do padrão será concluído em algum momentoMarço , mas vai demorar mais alguns meses para a ISO publicá-lo.Durante esse tempo, os criadores do compilador estão lançando recursos para que sejam o mais compatíveis com C ++ 0x possível quando o padrão for finalizado.

Eu acredito que a versão mais recente do GCC suporta a herança de construtores, então se você deve tentar agora, você pode usar.Obviamente, o suporte a C ++ 0x é experimental e sujeito a alterações à medida que bugs forem encontrados, etc.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top