detrazione Modello per la funzione in base al suo tipo di ritorno?
-
25-09-2019 - |
Domanda
Mi piacerebbe essere in grado di utilizzare template detrazione per raggiungere i seguenti:
GCPtr<A> ptr1 = GC::Allocate();
GCPtr<B> ptr2 = GC::Allocate();
al posto di (quello che ho attualmente):
GCPtr<A> ptr1 = GC::Allocate<A>();
GCPtr<B> ptr2 = GC::Allocate<B>();
Il mio attuale Assegnare sguardi funzione come questa:
class GC
{
public:
template <typename T>
static GCPtr<T> Allocate();
};
Questo sarebbe possibile staccare il <A>
extra e <B>
?
Soluzione
Questo non può essere fatto. Il tipo di ritorno non partecipa nel tipo di deduzione, è piuttosto un risultato di aver già abbinata la firma modello appropriato. È possibile, tuttavia, nascondere dalla maggior parte degli usi come:
// helper
template <typename T>
void Allocate( GCPtr<T>& p ) {
p = GC::Allocate<T>();
}
int main()
{
GCPtr<A> p = 0;
Allocate(p);
}
Sia che la sintassi è in realtà migliore o peggiore del GCPtr<A> p = GC::Allocate<A>()
iniziale è un'altra questione.
P.S. C ++ 11 vi permetterà di saltare una delle dichiarazioni di tipo:
auto p = GC::Allocate<A>(); // p is of type GCPtr<A>
Altri suggerimenti
L'unica cosa che mi viene in mente: make allocare un non-modello che restituisce un oggetto proxy non modello che ha un operatore di conversione su modelli che fa il vero lavoro:
template <class T>
struct GCPtr
{
};
class Allocator
{
public:
template <class T>
operator GCPtr<T>() { return GCPtr<T>(); }
};
class GC
{
public:
static Allocator Allocate() { return Allocator(); }//could give a call-back pointer?
};
int main()
{
GCPtr<int> p = GC::Allocate();
}
Si potrebbe andare il percorso inverso.
Se si sta utilizzando un aggiornato compilatore (MSVC 2010, che dovrebbe uscire in un paio di giorni, o la versione attuale di GCC) e non vi dispiace fare affidamento su C ++ 0x caratteristiche:
auto ptr1 = GC::Allocate<A>();
auto ptr2 = GC::Allocate<B>();
vuoi salvare il <A>
extra e <B>
, non solo sul lato destro della strada. :)
(Questa risposta è la stessa come @UncleBens, ma un po 'più generale in quanto perfetto-presentato alcuna argomentazione.)
Questo è molto utile in linguaggi come Haskell in cui, ad esempio, read
avrà una stringa come input e analizzerà secondo il tipo di ritorno desiderata.
( codice di esempio su Ideone .)
In primo luogo, iniziare con la foo
funzione il cui tipo di ritorno vogliamo dedurre:
template<typename Ret>
Ret foo(const char *,int);
template<>
std::string foo<std::string>(const char *s,int) { return s; }
template<>
int foo<int >(const char *,int i) { return i; }
Quando è stato chiesto per una stringa, che restituisca la stringa che è nel suo primo argomento. Quando è stato chiesto per un int, che restituisca il secondo argomento.
Si può definire un auto_foo
funzione che può essere utilizzato come segue:
int main() {
std::string s = auto_foo("hi",5); std::cout << s << std::endl;
int i = auto_foo("hi",5); std::cout << i << std::endl;
}
Per fare questo lavoro, abbiamo bisogno di un oggetto che memorizzare temporaneamente gli argomenti della funzione, e anche eseguire la funzione quando viene chiesto di Converti per il tipo di ritorno desiderata:
#include<tuple>
template<size_t num_args, typename ...T>
class Foo;
template<typename ...T>
class Foo<2,T...> : public std::tuple<T&&...>
{
public:
Foo(T&&... args) :
std::tuple<T&&...>(std::forward<T>(args)...)
{}
template< typename Return >
operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this)); }
};
template<typename ...T>
class Foo<3,T...> : std::tuple<T&&...>
{
public:
Foo(T&&... args) :
std::tuple<T&&...>(std::forward<T>(args)...)
{}
template< typename Return >
operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this), std::get<2>(*this)); }
};
template<typename ...T>
auto
auto_foo(T&&... args)
// -> Foo<T&&...> // old, incorrect, code
-> Foo< sizeof...(T), T&&...> // to count the arguments
{
return {std::forward<T>(args)...};
}
Inoltre, i lavori di cui sopra per le funzioni di due o tre arg-Arg, non è difficile vedere come estendere questo.
Questo è un sacco di codice da scrivere! Per ogni funzione si vuole applicare questo, si potrebbe scrivere una macro che fa per voi. Qualcosa di simile alla parte superiore del file:
REGISTER_FUNCTION_FOR_DEDUCED_RETURN_TYPE(foo); // declares
// necessary structure and auto_???
e quindi si potrebbe usare auto_foo
nel programma.
Allo stesso modo non si può sovraccaricare le funzioni sul tipo di ritorno, non si può fare la deduzione modello su di esso. E per la stessa ragione - se f () è un modello / sovraccarico che restituisce qualcosa, che tipo da utilizzare qui:
f();
Si potrebbe provare a utilizzare una macro per esso. Oltre a questo, non vedo come questo dovrebbe lavorare con una sola dichiarazione.
#define ALLOC(ptrname,type) GCPtr<type> ptrname = GC::Allocate<type>()
ALLOC(ptr1,A);
punti Johannes' sono validi. L'>> problema è facilmente risolto. Ma penso che con le virgole come parte del tipo richiede l'C99 preprocessore varargs estensione:
#define ALLOC(ptrname,...) GCPtr< __VA_ARGS__ > ptrname = GC::Allocate< __VA_ARGS__ >()
ALLOC(ptr1,SomeTemplate<int,short>);