5

Supongamos que deseo desarrollar una biblioteca genérica que se pueda usar con tipos numéricos, incluidos los tipos dobles y definidos por el usuario. El problema, que estoy enfrentando en este momento es que no sé cómo escribir el tipo de retorno de una plantilla de función muy similar a éste:Determinación del tipo de devolución de la "función genérica" ​​

template<class T> 
auto transmogrify(T x) 
-> ??? 
{ 
    using std::abs; 
    return abs(x)+2.0; 
} 

La declaración using hace que el trabajo del cuerpo de esta plantilla de función para los tipos primitivos porque estos no tienen un espacio de nombre asociado (y, por lo tanto, no hay una ADL). Pero quiero que Transmogrify use funciones de ABS especializadas en caso de que el autor de un tipo definido por el usuario proporcione su propia función de abs. No puedo simplemente usar

-> decltype(abs(x)+2.0) 

porque esto no funcionaría para, por ejemplo, se duplica desde std :: abs no es en su alcance (por lo que puedo decir). Pero al escribir

-> decltype(std::abs(x)+2.0) 

se desactivaría ADL. Pero deshabilitar ADL no es una opción. Además, el valor devuelto por una función de ABS especializada puede no ser de tipo T, sino de algún otro tipo.

Cualquier idea sobre cómo resolver el problema del tipo de devolución mientras (a) mantiene ADL y (b) recurre a alguna función predeterminada (como std :: abs en este caso) para tipos que no proporcionan un abs especializado .

+0

'#define ab usando std :: abs; your_template_fn #undef ab' no estoy seguro de si esa buena opción para hacer –

+0

¿alguien puede comentar lo anterior es bueno o no? –

+1

@ Mr.Anubis y cómo determinar el tipo de devolución de la función utilizando esta definición? – ForEveR

Respuesta

12

Use un espacio de nombre separado, donde puede poner la cláusula using. Esto evita la contaminación del espacio de nombres, ya que la cláusula de uso solo se aplica a ese espacio de nombres. Recomendaría nombrarlo como algo único, para que no lo desperdicie accidentalmente.

namespace transmog_detail 
{ 
    using std::abs; 

    template<class T> 
    auto transmogrify(T x) -> decltype(abs(x) + 2.0) 
    { 
     return abs(x) + 2.0; 
    } 
} 

// Then pull it into the current namespace, as recommended by @LucDanton. 
using transmog_detail::transmogrify; 

// Or if there is a reason, you can forward. 
// template<class T> 
// auto transmogrify(T x) 
// -> decltype(transmog_detail::transmogrify(x)) 
// { 
// return transmog_detail::transmogrify(x); 
// } 
+0

¡Muy listo! Espacios de nombre sin nombre pueden o no hacer esto más limpio. No es seguro. –

+0

¡Por supuesto! :) Gracias, Dave! – sellibitze

+0

@MooingDuck: Podría, o no. Si usa otros espacios de nombre sin nombre, también tendrán la cláusula de uso, que podría no ser deseable. –

-6

Las respuestas anteriores son buenas, pero la manera más sencilla que puedo pensar es utilizar el encabezado typeinfo. fue diseñado específicamente para determinar tipos y constructores de objetos.

ver aquí: http://www.cplusplus.com/reference/std/typeinfo/type_info/

+4

-1 para nada útil - type_info trata sobre la identificación del tipo de tiempo de ejecución, mientras que una declaración necesita un tipo determinado estáticamente. –

Cuestiones relacionadas