(Esta respuesta es la misma que @UncleBens, pero un poco más general, ya que perfecto transmita ningún argumento.)
Esto es muy útil en lenguajes como Haskell, donde, por ejemplo, se llevará a read
una cadena como entrada y la analizará de acuerdo con el tipo de devolución deseado.
(Aquí es sample code on ideone.)
En primer lugar, comenzar con la función foo
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 pide un int, devolverá el segundo argumento.
Podemos definir una función auto_foo
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 pide que convert 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, los trabajos anteriores para dos o arg arg funciones de tres, no es difícil ver cómo extender eso.
¡Esto es mucho código para escribir! Para cada función a la que aplicará esto, podría escribir una macro que haga esto 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 entonces se podría utilizar auto_foo
en su programa.
fwiw Tenía algo similar pero con un tipo de devolución basado en los tipos de argumentos del constructor. Hice una función auxiliar de plantilla 'make_complex_template_obj (the, args)', así que puedo usar 'auto' al iniciar las variables de esa función. presumiblemente por la misma razón que en la respuesta aceptada, a esa plantilla no se le pudo dar el tipo de retorno 'auto'. Afortunadamente, pude evitar duplicar el nombre de tipo en el 'return' porque para entonces sabía qué tipo venía y convirtió un _initialiser-list_ desnudo apropiadamente. toda una aventura! –