2010-06-18 12 views
11

Por favor, vea lo que estoy tratando de hacer:¿Por qué las especializaciones de plantillas no están permitidas en diferentes espacios de nombres?

#include <iostream> 
namespace first 
{ 
template <class T> 
class myclass 
{ 
    T t; 
public: 
    void who_are_you() const 
    { std::cout << "first::myclass"; } 
}; 
} 
namespace second 
{ 
using first::myclass; 
template <> 
class myclass <int> 
{ 
    int i, j; 
public: 
    void who_are_you() const 
    { std::cout << "second::myclass"; } 
}; 
} 

esto no está permitido. ¿Podría aclarar por qué no se pueden especializaciones en diferentes espacios de nombres, y cuáles son las soluciones disponibles? Además, ¿es algo fijo en C++ 0x?

Esto me permitiría, por ejemplo, a especializarse std::max, std::swap, std::numeric_limits, etc .. sin tener que recurrir a un comportamiento indefinido mediante la adición de algo que ::std::?


@AndreyT Así es como yo, aunque lo usaría:

// my_integer is a class 
std::numeric_limits<my_integer>::max(); // specialized std::numeric_limits for my_integer 

se puede hacer esto?

+0

Como alternativa, ¿no podría hacer una plantilla nueva que hereda de la estándar? – Cogwheel

+4

Según §17.4.3.1/1: "Un programa puede agregar especializaciones de plantilla para cualquier plantilla de biblioteca estándar al espacio de nombres std. Tal especialización (completa o parcial) de una plantilla de biblioteca estándar da como resultado un comportamiento indefinido a menos que la declaración dependa de un usuario -nombre definido de la vinculación externa y a menos que la especialización cumpla con los requisitos de la biblioteca estándar para la plantilla original ". Entonces, si bien existen restricciones, * puede * agregar tales especializaciones a ':: std ::' en las circunstancias adecuadas. –

+0

@jerry Coffin ¡Pensé que agregar algo daría como resultado un comportamiento indefinido! ¿Podría proporcionar una respuesta explicando cómo cumplir estos requisitos? – AraK

Respuesta

7

C++ 2003, §17.4.3.1/1: "Un programa puede agregar especializaciones de plantilla para cualquier plantilla de biblioteca estándar al espacio de nombres std. Tal especialización (completa o parcial) de una plantilla de biblioteca estándar da como resultado un comportamiento indefinido a menos que la declaración dependa de un nombre definido por el usuario la especialización cumple con los requisitos estándar de la biblioteca para la plantilla original ".

Como tal, se le permite especializarse una plantilla de biblioteca, y poner su especialización en espacio de nombres std, con tal de que depende de un tipo definido por el usuario y cumple con los requisitos de la plantilla original.

El código que tiene en su pregunta editada parece ser una especialización para un nombre definido por el usuario que (presumiblemente) tiene un enlace externo, por lo que no debería tener ningún problema con esa parte de las cosas.

Eso solo deja el requisito de que su especialización cumpla con los requisitos de la plantilla original. Para su tipo, la mayor parte de esto probablemente sea trivial. La única parte que puedo ver que podría no ser obvia es que parece que tienes que proporcionar una especialización para toda la plantilla, no solo numeric_limits::max(). Es decir, que tendrá que hacer algo así (ejemplo debe estar en el estadio para una de 128 bits de tipo entero sin signo):

namespace std { 
template <> 
class numeric_limits<my_integer> { 
public: 

    static const bool is_specialized = true; 
    static T min() throw() { return 0; 
    static T max() throw() { return /* 2^128-1 */; } // *** 
    static const int digits = 128; 
    static const int digits10 = 38; 
    static const bool is_signed = false; 
    static const bool is_integer = true; 
    static const bool is_exact = true; 
    static const int radix = 2; 
    static T epsilon() throw() { return 0; } 
    static T round_error() throw() { return 0; } 
    static const int min_exponent = 0; 
    static const int min_exponent10 = 0; 
    static const int max_exponent = 0; 
    static const int max_exponent10 = 0; 
    static const bool has_infinity = false; 
    static const bool has_quiet_NaN = false; 
    static const bool has_signaling_NaN = false; 
    static const float_denorm_style has_denorm = denorm_absent; 
    static const bool has_denorm_loss = false; 
    static T infinity() throw() { return 0; } 
    static T quiet_NaN() throw() { return 0; } 
    static T signaling_NaN() throw() { return 0; } 
    static T denorm_min() throw() { return 0; } 
    static const bool is_iec559 = false; 
    static const bool is_bounded = true; 
    static const bool is_modulo = true; 
    static const bool traps = false; 
    static const bool tinyness_before = false; 
    static const float_round_style round_style = round_toward_zero; 
}; 
} 

No pocos de ellos son realmente para este tipo de FP, y no está obligado ser significativo para un tipo entero; Creo que todavía necesitan ser implementados.

+0

Gracias por darnos la respuesta. Una pequeña aclaración, por favor, qué se entiende por vinculación externa. Si mi biblioteca es solo un encabezado, ¿el comportamiento no está definido? – AraK

+2

No - "enlace externo" significa que no es 'estático' o en un espacio de nombre anónimo. –

+0

Genial. Ahora es claro :) – AraK

-4

¿Por qué surgiría tal pregunta? Sin entender que es difícil incluso comenzar a responderlo.

La especialización modifica la plantilla principal. No es "separable" de ninguna manera de la plantilla principal. De cierta manera, como un concepto de alto nivel, sigue siendo la misma plantilla (aunque en un nivel inferior se define como una independiente). Entonces, por razones obvias, está en el mismo espacio de nombres que la plantilla principal.

Lo siento, no puedo dar una mejor explicación, ya que no entiendo cómo puede surgir una pregunta de este tipo.

BTW, ¿qué quiere decir con "en el espacio de nombres diferente"? ¿Desea que la especialización sea miembro de un espacio de nombres diferente? ¿O desea que su especialización se defina en un espacio de nombres diferente en el código fuente, pero que siga siendo un miembro del espacio de nombres original?

3

Se complica las cosas:

namespace first 
{ 
    template <class T> class TArray; 
} 

namespace second 
{ 
    using first::TArray; 

    template <class U> class TArray < Node<U> >; 
    //       ^
    // Only there do you realize it's a specialization and not another template 
} 

Entiendo su frustración, a menudo deseaban lo mismo. Parece definitivamente posible y ciertamente no compro el argumento de agrupación lógica, sin embargo, debo admitir que requeriría aún más esfuerzo de los escritores del compilador, y el análisis de C++ correctamente ya es lo suficientemente difícil como está.

Las plantillas son un poco desordenado en C++ si quieres mi opinión, pero entonces es fácil de decir, con el beneficio de la experiencia y después de haber visto 20 años de uso :)

+0

@Matthiew M. Gracias. Buena respuesta. – AraK

Cuestiones relacionadas