Pregunta

Me gustaría ser capaz de utilizar la deducción plantilla para lograr lo siguiente:

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

en lugar de (lo que tengo actualmente):

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

Mi actual Asignar miradas función como esta:

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

Sería esto posible desprender la <A> extra y <B>?

¿Fue útil?

Solución

Eso no se puede hacer. El tipo de retorno no participa en el tipo de deducción, es más bien una consecuencia de haber igualado ya la firma de plantilla apropiado. Puede, sin embargo, esconderse de la mayoría de los usos como:

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

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

Ya sea que la sintaxis es en realidad ni mejor ni peor que el GCPtr<A> p = GC::Allocate<A>() inicial es otra cuestión.

P.S. c ++ 11 permitirá que se salte una de las declaraciones de tipo:

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

Otros consejos

Lo único que puedo pensar: maquillaje asignar una plantilla que no devuelve un objeto de proxy no molde que tiene un operador de conversión de plantilla, que hace el trabajo real:

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

Se podía ir a la ruta opuesta.

Si está utilizando un compilador al día (MSVC 2010, que debería salir en un par de días, o la versión actual de GCC) y no les importa confiar en C ++ 0x cuenta:

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

tendría que guardar el <A> extra y <B>, pero no en el lado derecho. :)

(Esta respuesta es la misma que @UncleBens, pero un poco más general, ya que perfecto-presentado ningún argumento.)

Esto es muy útil en lenguajes como Haskell donde, por ejemplo, read tendrá una cadena como entrada y analizará de acuerdo con el tipo de retorno deseado.

(Aquí es código de ejemplo en Ideone .)

En primer lugar, comenzar con el foo función cuyo tipo de retorno deseamos deducir:

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

Cuando se le preguntó por una cadena, que va a devolver la cadena que está en su primer argumento. Cuando se le preguntó por un int, que va a devolver el segundo argumento.

Podemos definir una auto_foo función que se puede utilizar de la siguiente manera:

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

Para que esto funcione, necesitamos un objeto que va a almacenar temporalmente los argumentos de la función, y también ejecutar la función cuando se le preguntó a Convertir para el tipo de retorno deseada:

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

Además, lo anterior funciona para funciones de dos o tres arg-arg, no es difícil ver cómo extender eso.

Esta es una gran cantidad de código para escribir! Para cada función que se va a aplicar esto a, se podría escribir una macro que lo hace por usted. Algo como esto en la parte superior de su archivo:

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

y luego se podría utilizar auto_foo en su programa.

De la misma manera no se puede sobrecargar las funciones del tipo de cambio, usted no puede hacer la deducción de plantilla en él. Y por la misma razón - si f () es una plantilla / sobrecarga que vuelve algo, ¿qué tipo de uso aquí:

f();

Se podría tratar de usar una macro para ello. Aparte de eso, no veo la forma en que se supone que debe funcionar con una sola declaración.

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

ALLOC(ptr1,A);

puntos de Johannes son válidos. El >> problema se soluciona fácilmente. Pero creo que tienen comas como parte del tipo requiere que el preprocesador C99 varargs extensión:

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

ALLOC(ptr1,SomeTemplate<int,short>);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top