Frage

Ich möchte in der Lage sein Vorlage Abzug zu verwenden, um Folgendes zu erreichen:

GCPtr<A> ptr1 = GC::Allocate();
GCPtr<B> ptr2 = GC::Allocate();

statt (was ich derzeit haben):

GCPtr<A> ptr1 = GC::Allocate<A>();
GCPtr<B> ptr2 = GC::Allocate<B>();

Meine heutige Aussehen zuweisen Funktion wie folgt aus:

class GC
{
public:
    template <typename T>
    static GCPtr<T> Allocate();
};

Wäre dies möglich, die zusätzlichen <A> und <B> abzuzuschlagen?

War es hilfreich?

Lösung

Das kann nicht durchgeführt werden. Der Rückgabetyp nicht teilnimmt bei Typ-Abzug, ist es eher ein Ergebnis hat bereits die entsprechende Vorlage Signatur abgestimmt. Sie können trotzdem verstecken es von den meisten Anwendungen wie:

// helper
template <typename T>
void Allocate( GCPtr<T>& p ) {
   p = GC::Allocate<T>();
}

int main()
{
   GCPtr<A> p = 0;
   Allocate(p);
}

Ob das Syntax ist tatsächlich besser oder schlechter als die anfängliche GCPtr<A> p = GC::Allocate<A>() ist eine andere Frage.

P. S. c ++ 11 ermöglicht es Ihnen, eine der Typdeklarationen überspringen:

auto p = GC::Allocate<A>();   // p is of type GCPtr<A>

Andere Tipps

Das einzige, was ich mich vorstellen kann: make Vergeben Sie eine Nicht-Vorlage, dass die Renditen ein Nicht-Template-Proxy-Objekt, das einen Templat Konvertierungsoperator hat, die die eigentliche Arbeit tut:

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();
}

Sie können den umgekehrten Weg gehen.

Wenn Sie einen aktuellen Compiler (MSVC 2010, die in ein paar Tagen sein sollten, oder die aktuelle Version von GCC) verwenden und nicht dagegen auf C ++ 0x unter Berufung Features:

auto ptr1 = GC::Allocate<A>();
auto ptr2 = GC::Allocate<B>();

würden Sie die zusätzliche <A> und <B> sparen, nur nicht auf der rechten Seite. :)

(Diese Antwort ist die gleiche wie @UncleBens, aber ein bisschen mehr allgemein, da es vollkommen-Vorwärts-Argumente.)

Dies ist sehr nützlich in Sprachen wie Haskell, wo zum Beispiel, read wird eine Zeichenkette als Eingabe und parsen es entsprechend der gewünschten Rücklauftyp.

(Hier ist Beispielcode auf ideone .)

Starten Sie zunächst mit der Funktion foo deren Rückgabetyp wir ableiten wollen:

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; }

Wenn Sie nach einem String gefragt, wird es die Zeichenfolge zurück, die in ihrem ersten Argument ist. Wenn für einen int gefragt, es wird das zweite Argument zurück.

Wir können eine Funktion auto_foo definieren, die verwendet werden können, wie folgt:

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;
}

Um diese Arbeit zu machen, brauchen wir ein Objekt, das die Funktionsargumente vorübergehend gespeichert werden, und auch die Funktion ausgeführt werden, wenn es auf convert auf den gewünschten Rückgabetyp:

#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)...};
}

Auch die oben genannten Arbeiten für zwei argument oder drei argument Funktionen, es ist nicht schwer zu sehen, wie das verlängern.

Dies ist eine Menge Code zu schreiben! Für jede Funktion werden Sie dies anwenden, könnten Sie ein Makro schreiben, die dies für Sie tut. So etwas wie dies am Anfang der Datei:

REGISTER_FUNCTION_FOR_DEDUCED_RETURN_TYPE(foo); // declares
                        // necessary structure and auto_???

und dann könnte man auto_foo in Ihrem Programm verwenden.

In der gleichen Weise, die Sie nicht Funktionen auf Rückgabetyp überlasten können, können Sie Template-Abzug auf es nicht tun. Und aus dem gleichen Grunde - wenn f () ist eine Schablone / Überlast, dass die Renditen etwas, welche Art hier zu verwenden:

f();

Sie könnten versuchen, ein Makro für sie zu verwenden. Other than that, ich sehe nicht, wie das mit nur einer Anweisung an der Arbeit angenommen hat.

#define ALLOC(ptrname,type) GCPtr<type> ptrname = GC::Allocate<type>()

ALLOC(ptr1,A);

Johannes' Punkte sind gültig. Das >> Problem wird leicht behoben. Aber ich denke, mit Kommas als Teil der Art des C99 erfordert Präprozessor varargs Erweiterung:

#define ALLOC(ptrname,...) GCPtr< __VA_ARGS__ > ptrname = GC::Allocate< __VA_ARGS__ >()

ALLOC(ptr1,SomeTemplate<int,short>);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top