5

Supponiamo di voler sviluppare una libreria generica che dovrebbe essere utilizzabile con tipi di tipo numerico compresi tipi doppi e definiti dall'utente. Il problema, che sto affrontando in questo momento è che non so come scrivere il tipo di ritorno di una funzione di modello molto simile a questo:Determinazione del tipo di ritorno di "funzione generica" ​​

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

La dichiarazione utilizzando rende il lavoro del corpo di questo modello di funzione per i tipi primitivi perché questi non hanno uno spazio dei nomi associato (e quindi non c'è ADL). Ma voglio che la trasmogrificazione usi funzioni abs specialistiche nel caso in cui l'autore di un tipo definito dall'utente fornisca la sua funzione abs. Non posso semplicemente utilizzare

-> decltype(abs(x)+2.0) 

perché questo non avrebbe funzionato per, diciamo, dal momento che raddoppia std :: abs non è nel campo di applicazione (per quanto posso dire). Ma scrivere

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

disabilita ADL. Ma disabilitare ADL non è un'opzione. Inoltre, il valore restituito da una funzione abs specifica potrebbe non essere di tipo T ma di un altro tipo.

Eventuali idee su come risolvere il problema del tipo restituito mentre (a) mantenere ADL e (b) ricadere su alcune funzioni predefinite (come std :: abs in questo caso) per i tipi che non forniscono un abs specializzato .

+0

'# define ab utilizzando std :: abs; your_template_fn #undef ab' non è sicuro se quella buona scelta per fare –

+0

qualcuno possa commentare sopra la cosa è buona o no? –

+1

@ Mr.Anubis e in che modo determinare il tipo di funzione di restituzione che utilizza questa definizione? – ForEveR

risposta

12

Utilizzare uno spazio dei nomi separato, in cui è possibile inserire la clausola using. Ciò impedisce l'inquinamento dello spazio dei nomi, poiché la clausola using si applica solo a tale spazio dei nomi. Consiglierei di nominarlo qualcosa di unico, quindi non lo spargerai per caso.

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

Molto intelligente! Gli spazi dei nomi senza nome possono rendere questo pulitore o meno. Non sono sicuro. –

+0

Ovviamente! :) Grazie, Dave! – sellibitze

+0

@MooingDuck: Potrebbe, o potrebbe non esserlo. Se si utilizzano altri spazi dei nomi senza nome, avranno anche la clausola using, che potrebbe non essere desiderabile. –

-6

Le risposte di cui sopra sono buone, ma il modo in cui simoplest mi viene in mente è quello di utilizzare l'intestazione typeinfo. è stato specificamente progettato per determinare i tipi e i costruttori di oggetti.

vedere qui: http://www.cplusplus.com/reference/std/typeinfo/type_info/

+4

-1 per niente utile - type_info riguarda l'identificazione del tipo di runtime, mentre una dichiarazione richiede un tipo determinato staticamente. –

Problemi correlati