Domanda

Sto cercando di imparare le caratteristiche attualmente accettate di C ++ 11 e sto avendo problemi con auto e decltype. Come un esercizio di apprendimento che sto estendendo l'elenco classe std con alcune funzioni generiche.

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

Per la mappa membro voglio il tipo di ritorno per essere generico seconda di cosa la funzione ritorna passati. Così, per il tipo di ritorno avrei potuto fare qualcosa di simile.

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

Questo sarebbe anche bisogno di rimuovere il tipo galleggiante nel modello di funzione.

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

ho potuto utilizzare una classe template, ma che rende l'utilizzo di istanze più prolisso dal momento che ho per specificare il tipo di ritorno.

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

In sintesi della mia domanda sto cercando di capire come definire mappa senza utilizzare una classe template e hanno ancora generica nel tipo restituisce.

È stato utile?

Soluzione

Dato dalla std::list o altri contenitori std:: è sconsigliato.

Scrivi le tue operazioni funzioni libere in modo da poter lavorare su qualsiasi contenitore standard tramite iteratori.

Vuoi dire "definire mappa senza utilizzare una funzione di modello"?

Si dovrebbe essere in grado di utilizzare il tipo di membro result_type di std::function per ottenere il tipo restituisce.

Inoltre non è necessario per voi di specificare che la funzione viene passato come std::function. Si potrebbe lasciarla aperta come qualsiasi tipo, e lasciare che il compilatore uniscono tutto. Hai solo bisogno std::function per il polimorfismo runtime.

E l'utilizzo di nuovo per creare oggetti grezzo mucchio di assegnazione e restituirli con puntatore è trooooppo 1992! :)

La vostra funzione iter è essenzialmente la stessa cosa come il range based per ciclo .

Ma tutto ciò che a parte ... vuoi dire qualcosa di simile?

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

Questa sarà mai soddisfatta callable, e capire il tipo di ritorno della funzione utilizzando decltype.

Si noti che richiede _Ty essere costruibile di default. È possibile ottenere in giro che con la produzione di un'istanza:

template <class T>
T make_instance();

No attuazione è necessaria perché nessun codice viene generato che lo chiama, in modo che il linker non ha nulla di cui lamentarsi (grazie a dribeas per la precisazione!)

Così il codice diventa ora:

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

In alternativa, letteralmente, un elenco di qualsiasi tipo sarebbe si otterrebbe da chiamare la funzione f con un riferimento a un'istanza di _Ty.

E come bonus gratuito per accettare, cercare i riferimenti rvalue - questi significherà che si può scrivere:

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

E poi chiamare in questo modo:

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

A causa std :: elenco avrà una "mossa costruttore" (come un costruttore di copia, ma scelto quando l'argomento è una temporanea, come qui), si può rubare il contenuto del valore di ritorno, vale a dire fare lo stesso come un ottimale swap. Quindi non c'è la copia di tutta la lista. (Questo è il motivo per cui C ++ 0x farà ingenuamente scritto run codice esistente più veloce - molti trucchi popolari, ma brutte prestazioni diventerà obsoleta).

E si può ottenere lo stesso tipo di cosa per libero per qualsiasi classe esistente della propria, senza dover scrivere un costruttore mossa giusta, utilizzando unique_ptr.

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

Altri suggerimenti

Non è possibile utilizzare auto in argomenti della funzione in cui si desidera che i tipi degli argomenti da dedurre. Si utilizza modelli per questo. Dai un'occhiata a: http://thenewcpp.wordpress.com/2011/10/18/ la-parola-auto / e http://thenewcpp.wordpress.com/2011/10/25/ decltype-e-declval / . Entrambi spiegano come utilizzare auto e decltype. Essi dovrebbero dare abbastanza informazioni su come vengono utilizzati. In particolare, un'altra risposta su make_instance potrebbe essere fatto meglio con declval.

Credo che il punto che Jarrah stava facendo nella sua risposta è che quei punti spiegano esattamente come utilizzare queste cose. Io sottolineare i dettagli in ogni caso:

Non si può fare questo, ci sono due cose sbagliate:

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

auto non può essere utilizzato per gli argomenti della funzione. Se si desidera che il tipo di funzione da dedurre allora si dovrebbe utilizzare i modelli. La seconda è che decltype prende espressione, che è un tipo _Ty. Ecco come risolverlo:

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

In questo modo non v'è alcuna magia per creare un'istanza di un tipo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top