Pregunta

Estoy tratando de aprender las características actualmente aceptadas de C ++ 11 y tengo problemas con el auto y decltype. Como un ejercicio de aprendizaje les extiendo la lista de clase std con algunas funciones genéricas.

template<class _Ty, class _Ax = allocator<_Ty>>
class FList : public std::list<_Ty, _Ax>
{
public:
    void iter(const function<void (_Ty)>& f)
    {
        for_each(begin(), end(), f);
    }

    auto map(const function<float (_Ty)>& f) -> FList<float>*
    {
        auto temp = new FList<float>();

        for (auto i = begin(); i != end(); i++)
            temp->push_back(f(*i));

        return temp;
    }
};

auto *ints = new FList<int>();
ints->push_back(2);
ints->iter([](int i) { cout << i; });

auto *floats = ints->map([](int i) { return (float)i; });
floats->iter([](float i) { cout << i; });

En el mapa miembro Quiero el tipo de retorno para ser genérica dependiendo de lo que los rendimientos función pasada. Así que por el tipo de retorno que podría hacer algo como esto.

auto map(const function<float (_Ty)>& f) -> FList<decltype(f(_Ty))>*

Esto también tendría que quitar el tipo de flotador en la plantilla de función.

auto map(const function<auto (_Ty)>& f) -> FList<decltype(f(_Ty))>*

Podría utilizar una clase de plantilla, sino que hace que el uso de las instancias más detallado ya que tengo que especificar el tipo de retorno.

template<class T> FList<T>* map(const function<T (_Ty)>& f)

Para resumir de mi pregunta que estoy tratando de encontrar la manera de definir un mapa sin necesidad de utilizar una clase de plantilla y aún así tener que genérica en el tipo que devuelve.

¿Fue útil?

Solución

Derivado std::list o otros recipientes std:: no se recomienda.

Escriba sus operaciones de funciones como libre para que puedan funcionar en cualquier contenedor estándar a través de iteradores.

¿Se refiere a "definir un mapa sin necesidad de utilizar una función de plantilla"?

Usted debe ser capaz de utilizar el tipo de miembro de result_type std::function para obtener el tipo que devuelve.

Además, no es necesario que especifique que la función se pasa como un std::function. Se podía dejarla abierta como cualquier tipo, y dejar que el compilador se unen a todo. Sólo es necesario std::function para el polimorfismo en tiempo de ejecución.

Y el uso de nuevo para crear objetos Montón sin procesar de asignación y devolverlos al puntero es taaaan 1992! :)

Su función iter es esencialmente el mismo que el gama- basado bucle for .

Pero todo eso de lado ... Qué quiere decir algo como esto?

template <class TFunc>
auto map(const TFunc &f) -> FList<decltype(f(_Ty()))>*
{
    auto temp = new FList<decltype(f(_Ty()))>();

    for (auto i = begin(); i != end(); i++)
        temp->push_back(f(*i));

    return temp;
}

Esto coincidirá con nada puede ser llamado, y se darán cuenta el tipo de retorno de la función utilizando decltype.

Tenga en cuenta que se requiere _Ty ser construible por defecto. Usted puede obtener en torno a que mediante la fabricación de una instancia:

template <class T>
T make_instance();

No se requiere aplicación porque no se genera un código que llama, por lo que el enlazador no tiene nada que quejarse (gracias a dribeas por señalar esto!)

Así que el código se convierte ahora en:

FList<decltype(f(make_instance<_Ty>()))>*

O, literalmente, una lista de lo que sea el tipo que sería ponía de llamar a la función f con una referencia a una instancia de _Ty.

Y como prima libre para aceptar, buscar referencias rvalue - éstos significarán que se puede escribir:

std::list<C> make_list_somehow()
{
    std::list<C> result;
    // blah...
    return result;
}

Y a continuación, llamar de esta manera:

std::list<C> l(make_list_somehow());

Debido a std :: lista tendrá un "movimiento constructor" (como un constructor de copia, pero elige cuando el argumento es una temporal, como aquí), puede robar el contenido del valor de retorno, es decir, hacer lo mismo que una óptima swap. Así que no hay copia de toda la lista. (Esta es la razón por C ++ 0x hará ingenuamente escrito dirigido código existente más rápido - muchos trucos de rendimiento populares pero feos se convertirá en obsoleto).

Y se puede obtener el mismo tipo de cosas gratis para cualquier clase existente de su cuenta, sin tener que escribir un movimiento constructor correcta, mediante el uso de unique_ptr.

std::unique_ptr<MyThing> myThing(make_my_thing_somehow());

Otros consejos

No se puede utilizar automóviles en argumentos de la función en la que desea los tipos de los argumentos para ser deducidas. Utiliza plantillas para eso. Mira esto: http://thenewcpp.wordpress.com/2011/10/18/ la-palabra-auto / http://thenewcpp.wordpress.com/2011/10/25/ decltype-y-declval / . Ambos explican cómo usar el automóvil y decltype. Se le debe dar suficiente información sobre cómo se utilizan. En particular, otra respuesta sobre make_instance podría hacerse mejor con declval.

Creo que el punto de que Jarrah estaba haciendo en su respuesta es que esos puntos no explican exactamente cómo usar estas cosas. Voy a señalar los detalles de todas formas:

No se puede hacer esto, hay dos cosas mal:

auto map(const function<auto (_Ty)>& f) -> FList<decltype(f(_Ty))>*

auto no se puede utilizar para argumentos de la función. Si desea que el tipo de la función que se deduce, entonces debería usar plantillas. La segunda es que decltype toma una expresión, mientras que _Ty es un tipo. Aquí está la forma de resolverlo:

template <typename Ret>
auto
map(const function<Ret (_Ty)>& f)
  -> FList<decltype(f(declval<_Ty>()))>
{}

De esta manera no hay magia para crear una instancia de un tipo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top