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>?

È stato utile?

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>);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top