c++0x heredado constructor de plantillas
-
29-10-2019 - |
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?
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
oTTP<T>::TTP
conTTP
siendo una plantilla parámetro de plantilla). - Si la parte final coincide con el nombre de la clase (así,
foo::foo
oT::T
, conT
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
(dondeT
denota la clasefoo
) no funcionaría, porquefoo
no tiene ningún miembro de la llamadaT
.
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.