2012-02-08 20 views
13

que estoy acostumbrado paréntesis angulares se utilizan para especificar un tipo, como un parámetro:¿Qué son los corchetes angulares para los valores de los argumentos y para qué se utilizan?

vector<int> vecOfInts ; 

Pero en rapidjson, no hay código como este:

document.Parse<0>(json) ; 

La firma del método document.Parse es:

template <unsigned parseFlags> 
GenericDocument& Parse(const Ch* str) { 
    RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); 
    GenericStringStream<Encoding> s(str); 
    return ParseStream<parseFlags>(s); 
} 

yo no sabía que se podía pasar un valor en corchetes angulares laterales: los corchetes angulares de pensamiento se usaron solo para los tipos de letra.

¿Qué está haciendo aquí el código, y por qué está pasando un valor en los corchetes angulares?

¿Es esta una buena idea? ¿Cuando?

+0

posible duplicado de [Motivo de uso del parámetro de plantilla sin tipo en lugar del parámetro regular?] (Http://stackoverflow.com/questions/7395700/reason-for-using-non-type-template-parameter-instead- of-regular-parameter) –

+2

Buscar "parámetro de plantilla sin tipo". –

Respuesta

18

Hay dos factores diferentes aquí.

En primer lugar, es posible definir plantillas que se parametrizan sobre otras cosas que no sean solo tipos. Por ejemplo, aquí es un simple tipo de matriz:

template <typename T, size_t N> struct Array { 
    T arr[N]; 
}; 

Podemos usar esto como

Array<int, 137> myArray; 

Sabemos que vector<int> y vector<double> son diferentes tipos. Pero ahora también debemos señalar que Array<int,137> y Array<int,136> son tipos diferentes.

En segundo lugar, cuando se usan plantillas, el compilador debe poder calcular un valor para todos los argumentos de la plantilla. Cuando usa clases de plantilla, esta es la razón por la que normalmente especifica todos los argumentos de la plantilla. Usted no dice vector x, por ejemplo, sino que dice algo como vector<double> x. Al usar funciones de plantilla, la mayoría de las veces el compilador puede descifrar los argumentos. Por ejemplo, para utilizar std::sort, que acaba de decir algo así como

std::sort(v.begin(), v.end()); 

Sin embargo, también se podría escribir

std::sort<vector<int>::iterator>(v.begin(), v.end()); 

a ser más explícito. Pero a veces, tienes una función de plantilla para la cual no se pueden descifrar todos los argumentos. En su ejemplo, tenemos esto:

template <unsigned parseFlags> 
GenericDocument& Parse(const Ch* str) { 
    RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); 
    GenericStringStream<Encoding> s(str); 
    return ParseStream<parseFlags>(s); 
} 

en cuenta que el parámetro parseFlags plantilla no se puede deducir de solamente los argumentos de la función. Como resultado, para llamar a la función, debe especificar el parámetro de la plantilla, ya que de lo contrario el compilador no puede resolverlo. Es por eso que iba a escribir algo así como

Parse<0>(myString); 

Aquí, el 0 es un parámetro de plantilla (resuelta en tiempo de compilación), y myString es el argumento real (resuelta en tiempo de ejecución).

En realidad, puede tener métodos que combinan un poco de inferencia de tipo y un poco de parámetros de tipo explícito. Por ejemplo, en Boost, hay una función lexical_cast que puede realizar conversiones desde y hacia tipos de cadenas. La firma de la función de convertir de un tipo no-cadena a un tipo de cadena es

template <typename Target, typename Source> 
    Target lexical_cast(const Source& arg); 

Aquí, si se llama a lexical_cast, el compilador puede averiguar lo que es Source, pero no se puede deducir sin Target algunas pistas. Para utilizar lexical_cast, por lo tanto, que iba a escribir algo así como

std::string myString = boost::lexical_cast<std::string>(toConvertToString); 

De manera más general, el compilador dice que usted tiene que especificar un número de argumentos de plantilla (opcionalmente 0), y va a tratar de deducir el resto. Si puede, ¡genial! Si no, es un error en tiempo de compilación. El uso de este, si lo desea, puede escribir una función como

template <int IntArgument, typename TypeArgment> 
    void DoSomething(const TypeArgument& t) { 
     /* ... */ 
} 

Para llamar a esta función, usted tendría que invocar esta manera:

DoSomething<intArg>(otherArg); 

Aquí, esto funciona porque tiene que decirle explícitamente al compilador qué es IntArgument, pero luego el compilador puede deducir TypeArgument del tipo del argumento a DoSomething.

Espero que esto ayude!

Cuestiones relacionadas