Pergunta

Eu gostaria de poder usar dedução de modelo para alcançar o seguinte:

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

em vez de (o que eu tenho atualmente):

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

Minha função de alocação atual se parece com a seguinte:

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

Seria possível nocautear o extra <A> e <B>?

Foi útil?

Solução

Isso não pode ser feito. O tipo de retorno não participa da dedução do tipo, é o resultado de já ter correspondido à assinatura do modelo apropriada. Você pode, no entanto, escondê -lo da maioria dos usos como:

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

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

Se essa sintaxe é realmente melhor ou pior do que a inicial GCPtr<A> p = GC::Allocate<A>() é outra pergunta.

O PS C ++ 11 permitirá que você pule uma das declarações de tipo:

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

Outras dicas

A única coisa em que consigo pensar: faça alocar um não-tempo que retorne um objeto proxy que não seja do tempo que possui um operador de conversão modelo que faz o trabalho 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();
}

Você pode seguir o caminho oposto.

Se você estiver usando um compilador up up Det (MSVC 2010, que deve ser lançado em alguns dias ou a versão atual do GCC) e não se importa de confiar nos recursos C ++ 0x:

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

economizaria para você o extra <A> e <B>, apenas não do lado direito. :)

(Esta resposta é a mesma que @unclebens, mas um pouco mais geral, pois é perfeita para os argumentos.)

Isso é muito útil em idiomas como Haskell, onde, por exemplo, read Pegará uma string como entrada e a analisará de acordo com o tipo de retorno desejado.

(Aqui está Código de amostra em ideone.)

Primeiro, comece com a função foo cujo tipo de retorno desejamos deduzir:

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 solicitado uma string, ela retornará a string que está em seu primeiro argumento. Quando solicitado um INT, ele retornará o segundo argumento.

Podemos definir uma função auto_foo que pode ser usado da seguinte maneira:

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 fazer isso funcionar, precisamos de um objeto que armazenará temporariamente os argumentos da função e também executará a função quando for solicitado converter para o tipo de retorno desejado:

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

Além disso, o acima funciona para funções de dois ou três áreas, não é difícil ver como estendê-lo.

Isso é muito código para escrever! Para cada função para a qual você aplicará isso, você pode escrever uma macro que faça isso por você. Algo assim no topo do seu arquivo:

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

E então você pode usar auto_foo em seu programa.

Da mesma maneira que você não pode sobrecarregar as funções no tipo de retorno, você não pode fazer dedução do modelo. E pelo mesmo motivo - se f () é um modelo/sobrecarga que retorna algo, que tipo de usar aqui:

f();

Você pode tentar usar uma macro para isso. Fora isso, não vejo como isso deve funcionar com apenas uma declaração.

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

ALLOC(ptr1,A);

Os pontos de Johannes são válidos. O problema >> é facilmente corrigido. Mas acho que ter vírgulas como parte do tipo exige a extensão do pré -processador C99:

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

ALLOC(ptr1,SomeTemplate<int,short>);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top