Le funzioni del modello possono essere sovraccaricate dal solo tipo di ritorno, a differenza delle normali funzioni.
template <typename T> int f() { return 1; }
template <typename T> long f() { return 2; }
int main() {
int (&f1)() = f<void>;
long (&f2)() = f<void>;
return f1() == f2();
}
Qui, ipotizzando un compilatore non ottimizzare, il complesso generato conterrà due funzioni f<void>()
, ma non possono condividere lo stesso nome alterato, o non ci sarebbe modo per il montaggio generato per main
per specificare quale delle istanze cui si riferisce.
In genere, se si dispone di una funzione modello sovraccarico, solo una delle definizioni verrà utilizzata per un argomento modello specifico, quindi questo non è comune, ma nei commenti sulla risposta di Columbo, dyp ha trovato l'idea di base su come questo potrebbe effettivamente essere utile. In Can addressof() be implemented as constexpr function?, mi si avvicinò con
template <bool>
struct addressof_impl;
template <>
struct addressof_impl<false> {
template <typename T>
static constexpr T *impl(T &t) {
return &t;
}
};
template <>
struct addressof_impl<true> {
template <typename T>
static /* not constexpr */ T *impl(T &t) {
return reinterpret_cast<T *>(&const_cast<char &>(reinterpret_cast<const volatile char &>(t)));
}
};
template <typename T>
constexpr T *addressof(T &t)
{
return addressof_impl<has_overloaded_addressof_operator<T>::value>::template impl<T>(t);
}
ma questo è in realtà una violazione di ODR se lo stesso esemplificazione addressof<X>
viene utilizzato in molteplici unità di traduzione, alcuni dove X
è incompleto, e alcuni dove X
è completo e dispone di un sovraccarico &
operatore. Questo può essere rielaborato eseguendo direttamente la logica all'interno di addressof
, usando normali funzioni sovraccariche.
template <typename T>
std::enable_if_t<has_overloaded_addressof_operator<T>::value, T *>
addressof(T &t)
{
return reinterpret_cast<T *>(&const_cast<char &>(reinterpret_cast<const volatile char &>(t)));
}
template <typename T>
constexpr
std::enable_if_t<!has_overloaded_addressof_operator<T>::value, T *>
addressof(T &t)
{
return &t;
}
(. has_overloaded_addressof_operator
avrebbe bisogno di essere inline troppo, per lo stesso motivo)
In questo modo, il problema viene evitato: quando X
è incompleta, quindi addressof<X>
si riferisce ad una funzione diversa rispetto a quando X
è completare.
@ dyp Ho provato, come è ora? – Columbo
Davvero un bell'esempio. Stavo anche pensando: l'ODR potrebbe essere violato se il tipo di reso non fosse parte della firma? Per esempio. se si ha il primo modello in TU 0 e il secondo in TU 1. – dyp
@dyp Sì, IIRC le dichiarazioni devono essere costituite dalla stessa sequenza di token (o una sequenza equivalente di token, per alcune definizioni di equivalenti), se si verificano alla stessa entità – Columbo