Pregunta

Aquí está la clase foo:

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

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

Aquí es de la clase de la barra:

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

Es la sintaxis correcta para la herencia de los constructores?Si yo uso el "uso de foo::foo;" entonces el compilador de Visual C++ 2010 muere.Así que, básicamente, cómo se heredan los constructores de las clases de plantilla en VC++ 2010?

¿Fue útil?

Solución

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

A dejar que esto analizar correctamente, usted tendría que insertar template antes de la foo<T>;, para indicar al compilador que foo es considerado como un nombre de plantilla (se puede mirar en foo<T> decirle a sí mismo, ya que T se desconoce).Pero el uso de ::template no está permitido en el uso de la declaración.El nombre no se refiere a todos los constructores de bar:En su lugar, haría referencia a una específica función de constructor de plantilla de especialización (T es el argumento de plantilla) de dicho constructor de la siguiente manera

template<typename T>
foo();

Además, no son válidos para un uso declaración de utilizar un template-id (como foo<T> como su nombre (que en efecto lo prohíbe para referirse a la función de la plantilla de la especialización, con la adición de prohibir a nombre de la función de conversión de especializaciones de plantilla indicó también), por lo que incluso si usted corrige el problema de análisis utilizando ::template (si es posible), aún el error en este punto.

Cuando se hereda de los constructores, se introdujeron reglas especiales fueron añadidos que permiten hacer referencia a un constructor utilizando una regla sintáctica:Si usted tiene un calificado-id (que, básicamente, un nombre completo utilizando ...::...), y el último calificado antes de la parte final de los nombres de una clase específica, entonces se puede denotar el constructor(s) de esa clase en dos formas adicionales:

  • Si la clase fue nombrado el uso de una plantilla-id (un nombre de la forma foo<T>) y la parte final coincide con el nombre de la plantilla, de modo que, foo<T>::foo o TTP<T>::TTP con TTP siendo una plantilla parámetro de plantilla).
  • Si la parte final coincide con el nombre de la clase (así, foo::foo o T::T, con T siendo un parámetro de plantilla).

Estas dos reglas adicionales sólo están activas en el uso de la declaración.Y ellos fueron, naturalmente, no está presente en C++03.La otra regla que también estuvo presente en C++03 es:Si la parte final de los nombres de la inyección nombre de la clase, entonces esta calificado nombre también se refiere a que el constructor:

  • foo::foo sería por ello el trabajo.Pero con esta regla solo, T::T (donde T denota la clase foo) no funcionaría, porque foo no tiene ningún miembro de la llamada T.

Para ello, con las reglas especiales en el lugar que usted puede escribir

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

La segunda es válido también: foo es la inyección nombre de la clase que se inyecta en la clase base foo<T> y heredado a bar.Nos referimos a ese nombre por bar::foo, y , a continuación, añadir la última parte foo, que se refiere a la inyección nombre de la clase de nuevo, para denotar el constructor(s) de `foo.

Ahora entiendo por qué el nombre inicial intentó haría referencia a una función constructora de la plantilla de especialización (si se permite):Debido a que el foo<T>::foo parte del nombre de todos los constructores, y el <T> que seguiría sería entonces el filtro de la plantilla y de paso el tipo de argumento.

Otros consejos

Si su compilador aún no admite la herencia de constructores, pero sí admite macros variadic, plantillas variadic y referencias rvalue, y un type_trait realmente útil, aquí hay una solución muy 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';
}

Si aún no tiene is_constructible, la idea básica funciona sin él, pero el "constructor heredado" será demasiado codicioso.

no necesita el segundo parámetro de plantilla;

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

debería hacer

editar Retiro que esto funciona en g ++ - 4.4.1, sin embargo, esta debería ser la sintaxis correcta cuando la función esté disponible

Las otras respuestas ya han hecho un buen trabajo al explicar cómo funcionan los constructores heredados en C ++ 0x.Sin embargo, al momento de escribir este artículo, ningún compilador ha implementado por completo el conjunto completo de características de C ++ 0x.Desafortunadamente, eso significa que VC ++ 2010 aún no admite la herencia de constructores.

El estándar C ++ 0x aún no se ha publicado.El borrador final del estándar estará terminado en algún momento deMarzo , pero ISO tardará unos meses más en publicarlo.Durante ese tiempo, los escritores de compiladores están implementando características para que sean lo más compatibles con C ++ 0x cuando se finalice el estándar.

Creo que la última versión de GCC admite la herencia de constructores, así que si debes probarla ahora, puedes usarla.Por supuesto, la compatibilidad con C ++ 0x es experimental y está sujeta a cambios a medida que se encuentren errores, etc.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top